Merge "[webview] Rename force dark WebView settings."
diff --git a/Android.bp b/Android.bp
index b4ce5de..4e7aa5f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,7 +110,6 @@
         "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
         "core/java/android/app/role/IRoleController.aidl",
         "core/java/android/app/role/IRoleManager.aidl",
-        "core/java/android/app/role/IRoleManagerCallback.aidl",
         "core/java/android/app/slice/ISliceManager.aidl",
         "core/java/android/app/slice/ISliceListener.aidl",
         "core/java/android/app/timedetector/ITimeDetectorService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 8e2c863..f329a38 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5262,7 +5262,7 @@
     method public int describeContents();
     method public boolean getAllowSystemGeneratedContextualActions();
     method public int getBadgeIconType();
-    method public android.app.Notification.BubbleMetadata getBubbleMetadata();
+    method @Nullable public android.app.Notification.BubbleMetadata getBubbleMetadata();
     method public String getChannelId();
     method public String getGroup();
     method public int getGroupAlertBehavior();
@@ -5479,25 +5479,25 @@
   public static final class Notification.BubbleMetadata implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getAutoExpandBubble();
-    method public android.app.PendingIntent getDeleteIntent();
+    method @Nullable public android.app.PendingIntent getDeleteIntent();
     method public int getDesiredHeight();
-    method public android.graphics.drawable.Icon getIcon();
-    method public android.app.PendingIntent getIntent();
+    method @NonNull public android.graphics.drawable.Icon getIcon();
+    method @NonNull public android.app.PendingIntent getIntent();
     method public boolean getSuppressInitialNotification();
     method @Deprecated public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
   }
 
-  public static class Notification.BubbleMetadata.Builder {
+  public static final class Notification.BubbleMetadata.Builder {
     ctor public Notification.BubbleMetadata.Builder();
-    method public android.app.Notification.BubbleMetadata build();
-    method public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
-    method public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent);
-    method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
-    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 @NonNull public android.app.Notification.BubbleMetadata build();
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(@Nullable android.app.PendingIntent);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
     method @Deprecated public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
   }
 
@@ -5522,7 +5522,7 @@
     method @NonNull public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
     method @NonNull public android.app.Notification.Builder setAutoCancel(boolean);
     method @NonNull public android.app.Notification.Builder setBadgeIconType(int);
-    method @NonNull public android.app.Notification.Builder setBubbleMetadata(android.app.Notification.BubbleMetadata);
+    method @NonNull public android.app.Notification.Builder setBubbleMetadata(@Nullable android.app.Notification.BubbleMetadata);
     method @NonNull public android.app.Notification.Builder setCategory(String);
     method @NonNull public android.app.Notification.Builder setChannelId(String);
     method @NonNull public android.app.Notification.Builder setChronometerCountDown(boolean);
@@ -6752,7 +6752,8 @@
     method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
     method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
     method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
-    method public int setGlobalPrivateDns(@NonNull android.content.ComponentName, int, @Nullable String);
+    method public int setGlobalPrivateDnsModeOpportunistic(@NonNull android.content.ComponentName);
+    method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
     method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
     method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
     method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
@@ -7731,6 +7732,7 @@
     field public static final int ACTIVITY_STOPPED = 23; // 0x17
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
     field public static final int DEVICE_SHUTDOWN = 26; // 0x1a
+    field public static final int DEVICE_STARTUP = 27; // 0x1b
     field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
     field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
     field public static final int KEYGUARD_HIDDEN = 18; // 0x12
@@ -12282,6 +12284,7 @@
     method public final void flushLayoutCache();
     method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimatorRes @AnimRes int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
+    method @AnyRes public static int getAttributeSetSourceResId(@Nullable android.util.AttributeSet);
     method public boolean getBoolean(@BoolRes int) throws android.content.res.Resources.NotFoundException;
     method @Deprecated @ColorInt public int getColor(@ColorRes int) throws android.content.res.Resources.NotFoundException;
     method @ColorInt public int getColor(@ColorRes int, @Nullable android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
@@ -14248,7 +14251,7 @@
     method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Insets> CREATOR;
-    field public static final android.graphics.Insets NONE;
+    field @NonNull public static final android.graphics.Insets NONE;
     field public final int bottom;
     field public final int left;
     field public final int right;
@@ -29942,6 +29945,8 @@
     method public int getLinkSpeed();
     method public String getMacAddress();
     method public int getNetworkId();
+    method @Nullable public String getPasspointFqdn();
+    method @Nullable public String getPasspointProviderFriendlyName();
     method public int getRssi();
     method @IntRange(from=0xffffffff) public int getRxLinkSpeedMbps();
     method public String getSSID();
@@ -30187,7 +30192,7 @@
   }
 
   public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable {
-    ctor public ParcelablePeerHandle(android.net.wifi.aware.PeerHandle);
+    ctor public ParcelablePeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR;
@@ -30255,16 +30260,6 @@
     field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
   }
 
-  public static final class WifiAwareManager.NetworkSpecifierBuilder {
-    ctor public WifiAwareManager.NetworkSpecifierBuilder();
-    method @NonNull public android.net.NetworkSpecifier build();
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPort(int);
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPskPassphrase(@NonNull String);
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setTransportProtocol(int);
-  }
-
   public final class WifiAwareNetworkInfo implements android.os.Parcelable android.net.TransportInfo {
     method public int describeContents();
     method @Nullable public java.net.Inet6Address getPeerIpv6Addr();
@@ -30274,6 +30269,22 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkInfo> CREATOR;
   }
 
+  public final class WifiAwareNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkSpecifier> CREATOR;
+  }
+
+  public static final class WifiAwareNetworkSpecifier.Builder {
+    ctor public WifiAwareNetworkSpecifier.Builder();
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(int);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(int);
+  }
+
   public class WifiAwareSession implements java.lang.AutoCloseable {
     method public void close();
     method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, @NonNull byte[]);
@@ -35485,6 +35496,7 @@
     field public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
     field public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
     field public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
+    field public static final String DISALLOW_CONTENT_SUGGESTIONS = "no_content_suggestions";
     field public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
     field public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
     field public static final String DISALLOW_DATA_ROAMING = "no_data_roaming";
@@ -43968,7 +43980,6 @@
     field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
     field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
     field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
-    field public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
     field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
     field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
@@ -45078,14 +45089,14 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
     method public int getCarrierIdFromSimMccMnc();
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.telephony.CellLocation getCellLocation();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
     method public int getDataActivity();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType();
     method public int getDataState();
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
     method public String getIccAuthentication(int, int, String);
@@ -45137,9 +45148,9 @@
     method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
     method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
     method public boolean isConcurrentVoiceAndDataSupported();
-    method public boolean isCurrentEmergencyNumber(@NonNull String);
     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 isEmergencyNumber(@NonNull String);
     method public boolean isHearingAidCompatibilitySupported();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isMultisimSupported();
     method public boolean isNetworkRoaming();
@@ -45459,15 +45470,13 @@
   public final class EmergencyNumber implements java.lang.Comparable<android.telephony.emergency.EmergencyNumber> android.os.Parcelable {
     method public int compareTo(@NonNull android.telephony.emergency.EmergencyNumber);
     method public int describeContents();
-    method public String getCountryIso();
+    method @NonNull public String getCountryIso();
     method public int getEmergencyCallRouting();
-    method public int getEmergencyNumberSourceBitmask();
-    method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
-    method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
-    method public int getEmergencyServiceCategoryBitmask();
+    method @NonNull public java.util.List<java.lang.Integer> getEmergencyNumberSources();
+    method @NonNull public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
     method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
-    method public String getMnc();
-    method public String getNumber();
+    method @NonNull public String getMnc();
+    method @NonNull public String getNumber();
     method public boolean isFromSources(int);
     method public boolean isInEmergencyServiceCategories(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -50072,7 +50081,7 @@
   }
 
   public class Surface implements android.os.Parcelable {
-    ctor public Surface(android.view.SurfaceControl);
+    ctor public Surface(@NonNull android.view.SurfaceControl);
     ctor public Surface(android.graphics.SurfaceTexture);
     method public int describeContents();
     method public boolean isValid();
@@ -50106,10 +50115,10 @@
 
   public static class SurfaceControl.Builder {
     ctor public SurfaceControl.Builder();
-    method public android.view.SurfaceControl build();
-    method public android.view.SurfaceControl.Builder setBufferSize(@IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.SurfaceControl build();
+    method @NonNull public android.view.SurfaceControl.Builder setBufferSize(@IntRange(from=0) int, @IntRange(from=0) int);
     method @NonNull public android.view.SurfaceControl.Builder setFormat(int);
-    method public android.view.SurfaceControl.Builder setName(String);
+    method @NonNull public android.view.SurfaceControl.Builder setName(@NonNull String);
     method @NonNull public android.view.SurfaceControl.Builder setOpaque(boolean);
     method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl);
   }
@@ -50838,8 +50847,8 @@
     method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, Object, int);
     method public boolean startNestedScroll(int);
     method public void stopNestedScroll();
-    method public void transformMatrixToGlobal(android.graphics.Matrix);
-    method public void transformMatrixToLocal(android.graphics.Matrix);
+    method public void transformMatrixToGlobal(@NonNull android.graphics.Matrix);
+    method public void transformMatrixToLocal(@NonNull android.graphics.Matrix);
     method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable);
     method public final void updateDragShadow(android.view.View.DragShadowBuilder);
@@ -53459,11 +53468,6 @@
 
 package android.view.inspector {
 
-  public class GeneratedInspectionCompanionProvider implements android.view.inspector.InspectionCompanionProvider {
-    ctor public GeneratedInspectionCompanionProvider();
-    method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
-  }
-
   public interface InspectionCompanion<T> {
     method @Nullable public default String getNodeName();
     method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
@@ -53544,6 +53548,11 @@
     ctor public PropertyReader.PropertyTypeMismatchException(int, @NonNull String, @NonNull String);
   }
 
+  public class StaticInspectionCompanionProvider implements android.view.inspector.InspectionCompanionProvider {
+    ctor public StaticInspectionCompanionProvider();
+    method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
+  }
+
   public final class WindowInspector {
     method @NonNull public static java.util.List<android.view.View> getGlobalWindowViews();
   }
@@ -53615,7 +53624,6 @@
     method public int describeContents();
     method @Nullable public String getCallingPackageName();
     method @NonNull public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation();
-    method @Nullable public String getConversationId();
     method @Nullable public java.util.List<java.lang.String> getHints();
     method @IntRange(from=0xffffffff) public int getMaxSuggestions();
     method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig();
@@ -53628,7 +53636,6 @@
   public static final class ConversationActions.Request.Builder {
     ctor public ConversationActions.Request.Builder(@NonNull java.util.List<android.view.textclassifier.ConversationActions.Message>);
     method @NonNull public android.view.textclassifier.ConversationActions.Request build();
-    method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(@Nullable String);
     method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setHints(@Nullable java.util.List<java.lang.String>);
     method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(@IntRange(from=0xffffffff) int);
     method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig);
@@ -54712,8 +54719,8 @@
     method @NonNull public static ClassLoader getWebViewClassLoader();
     method public android.webkit.WebViewClient getWebViewClient();
     method @NonNull public android.os.Looper getWebViewLooper();
-    method @Nullable public android.webkit.WebViewRenderer getWebViewRenderer();
-    method @Nullable public android.webkit.WebViewRendererClient getWebViewRendererClient();
+    method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
+    method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
@@ -54763,8 +54770,8 @@
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
     method public void setWebViewClient(android.webkit.WebViewClient);
-    method public void setWebViewRendererClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRendererClient);
-    method public void setWebViewRendererClient(@Nullable android.webkit.WebViewRendererClient);
+    method public void setWebViewRenderProcessClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRenderProcessClient);
+    method public void setWebViewRenderProcessClient(@Nullable android.webkit.WebViewRenderProcessClient);
     method @Deprecated public boolean shouldDelayChildPressedState();
     method @Deprecated public boolean showFindDialog(@Nullable String, boolean);
     method public static void startSafeBrowsing(@NonNull android.content.Context, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
@@ -54880,14 +54887,15 @@
     method @Deprecated public android.webkit.WebView getWebView();
   }
 
-  public abstract class WebViewRenderer {
+  public abstract class WebViewRenderProcess {
+    ctor public WebViewRenderProcess();
     method public abstract boolean terminate();
   }
 
-  public abstract class WebViewRendererClient {
-    ctor public WebViewRendererClient();
-    method public abstract void onRendererResponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
-    method public abstract void onRendererUnresponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
+  public abstract class WebViewRenderProcessClient {
+    ctor public WebViewRenderProcessClient();
+    method public abstract void onRenderProcessResponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderProcess);
+    method public abstract void onRenderProcessUnresponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderProcess);
   }
 
 }
@@ -56265,7 +56273,7 @@
     method public String[] getDisplayedValues();
     method public int getMaxValue();
     method public int getMinValue();
-    method public int getSelectionDividerHeight();
+    method @Px public int getSelectionDividerHeight();
     method @ColorInt public int getTextColor();
     method @FloatRange(from=0.0, fromInclusive=false) public float getTextSize();
     method public int getValue();
diff --git a/api/system-current.txt b/api/system-current.txt
index 4d340a2..beacace 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1118,37 +1118,31 @@
 
   public abstract class RoleControllerService extends android.app.Service {
     ctor public RoleControllerService();
-    method public abstract void onAddRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
+    method @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
-    method public abstract void onClearRoleHolders(@NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
-    method public abstract void onGrantDefaultRoles(@NonNull android.app.role.RoleManagerCallback);
+    method @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
+    method @WorkerThread public abstract boolean onGrantDefaultRoles();
     method public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
     method public abstract boolean onIsRoleVisible(@NonNull String);
-    method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
-    method public abstract void onSmsKillSwitchToggled(boolean);
+    method @WorkerThread public abstract boolean onRemoveRoleHolder(@NonNull String, @NonNull String, int);
     field public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
   }
 
   public final class RoleManager {
     method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
     field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
   }
 
-  public interface RoleManagerCallback {
-    method public void onFailure();
-    method public void onSuccess();
-  }
-
 }
 
 package android.app.usage {
@@ -1576,6 +1570,7 @@
     method public boolean getAllocateAggressive();
     method @Deprecated public boolean getAllowDowngrade();
     method public boolean getDontKillApp();
+    method public boolean getEnableRollback();
     method @Nullable public String[] getGrantedRuntimePermissions();
     method public boolean getInstallAsFullApp(boolean);
     method public boolean getInstallAsInstantApp(boolean);
@@ -1587,7 +1582,7 @@
     method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method @Deprecated public void setAllowDowngrade(boolean);
     method public void setDontKillApp(boolean);
-    method public void setEnableRollback();
+    method public void setEnableRollback(boolean);
     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);
@@ -1822,18 +1817,18 @@
 
   public final class PackageRollbackInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public String getPackageName();
-    method public android.content.pm.VersionedPackage getVersionRolledBackFrom();
-    method public android.content.pm.VersionedPackage getVersionRolledBackTo();
+    method @NonNull public String getPackageName();
+    method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom();
+    method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
   }
 
   public final class RollbackInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
+    method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
     method public int getCommittedSessionId();
-    method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
+    method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
     method public int getRollbackId();
     method public boolean isStaged();
     method public void writeToParcel(android.os.Parcel, int);
@@ -1843,7 +1838,7 @@
   public final class RollbackManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
@@ -4739,8 +4734,6 @@
   }
 
   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();
   }
@@ -4981,8 +4974,8 @@
     method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
   }
 
-  public static final class WifiAwareManager.NetworkSpecifierBuilder {
-    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPmk(@NonNull byte[]);
+  public static final class WifiAwareNetworkSpecifier.Builder {
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]);
   }
 
   public class WifiAwareSession implements java.lang.AutoCloseable {
@@ -5190,7 +5183,7 @@
     method @Nullable public Object onTransactStarted(@NonNull android.os.IBinder, int);
   }
 
-  public class BugreportManager {
+  public final class BugreportManager {
     method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
     method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
@@ -5199,7 +5192,7 @@
     ctor public BugreportManager.BugreportCallback();
     method public void onError(int);
     method public void onFinished();
-    method public void onProgress(float);
+    method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
     field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
     field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
     field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
@@ -5208,7 +5201,7 @@
   }
 
   public final class BugreportParams {
-    ctor public BugreportParams(@android.os.BugreportParams.BugreportMode int);
+    ctor public BugreportParams(int);
     method public int getMode();
     field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
     field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
@@ -5218,9 +5211,6 @@
     field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"BUGREPORT_MODE_"}, value={android.os.BugreportParams.BUGREPORT_MODE_FULL, android.os.BugreportParams.BUGREPORT_MODE_INTERACTIVE, android.os.BugreportParams.BUGREPORT_MODE_REMOTE, android.os.BugreportParams.BUGREPORT_MODE_WEAR, android.os.BugreportParams.BUGREPORT_MODE_TELEPHONY, android.os.BugreportParams.BUGREPORT_MODE_WIFI}) public static @interface BugreportParams.BugreportMode {
-  }
-
   public static class Build.VERSION {
     field public static final String PREVIEW_SDK_FINGERPRINT;
   }
@@ -5610,7 +5600,6 @@
   }
 
   public class UserManager {
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean canSwitchUsers();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
@@ -5620,6 +5609,7 @@
     method @Nullable @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 @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
     method public boolean hasRestrictedProfiles();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser();
@@ -5627,7 +5617,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
     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 boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
     field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
@@ -5637,6 +5627,10 @@
     field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
     field public static final int RESTRICTION_SOURCE_PROFILE_OWNER = 4; // 0x4
     field public static final int RESTRICTION_SOURCE_SYSTEM = 1; // 0x1
+    field public static final int SWITCHABILITY_STATUS_OK = 0; // 0x0
+    field public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 4; // 0x4
+    field public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1; // 0x1
+    field public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 2; // 0x2
   }
 
   public static final class UserManager.EnforcingUser implements android.os.Parcelable {
@@ -5853,6 +5847,7 @@
   }
 
   public final class DeviceConfig {
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(String, String, boolean);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(String, String, float);
@@ -5860,7 +5855,8 @@
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(String, String, long);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(String, String, String);
-    method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
+    method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+    method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
     field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
@@ -5895,8 +5891,11 @@
     field public static final String NAMESPACE = "intelligence_attention";
   }
 
+  public static interface DeviceConfig.OnPropertiesChangedListener {
+    method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
+  }
+
   public static interface DeviceConfig.OnPropertyChangedListener {
-    method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
     method public void onPropertyChanged(String, String, String);
   }
 
@@ -8067,10 +8066,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
-    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 @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
     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();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
@@ -8212,6 +8211,7 @@
   }
 
   public final class DataProfile implements android.os.Parcelable {
+    method public int describeContents();
     method @NonNull public String getApn();
     method public int getAuthType();
     method public int getBearerBitmap();
@@ -8229,6 +8229,8 @@
     method public boolean isEnabled();
     method public boolean isPersistent();
     method public boolean isPreferred();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
     field public static final int TYPE_3GPP = 1; // 0x1
     field public static final int TYPE_3GPP2 = 2; // 0x2
     field public static final int TYPE_COMMON = 0; // 0x0
@@ -8460,7 +8462,7 @@
     method public static int getCallTypeFromVideoState(int);
     method public int getEmergencyCallRouting();
     method public int getEmergencyServiceCategories();
-    method public java.util.List<java.lang.String> getEmergencyUrns();
+    method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
     method public int getRestrictCause();
     method public int getServiceType();
@@ -8478,7 +8480,7 @@
     method public void setEmergencyCallRouting(int);
     method public void setEmergencyCallTesting(boolean);
     method public void setEmergencyServiceCategories(int);
-    method public void setEmergencyUrns(java.util.List<java.lang.String>);
+    method public void setEmergencyUrns(@NonNull java.util.List<java.lang.String>);
     method public void setHasKnownUserIntentEmergency(boolean);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
@@ -9846,8 +9848,8 @@
     method public int getVisibleTitleHeight();
     method public android.webkit.WebChromeClient getWebChromeClient();
     method public android.webkit.WebViewClient getWebViewClient();
-    method public android.webkit.WebViewRenderer getWebViewRenderer();
-    method public android.webkit.WebViewRendererClient getWebViewRendererClient();
+    method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
+    method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
     method public android.view.View getZoomControls();
     method public void goBack();
     method public void goBackOrForward(int);
@@ -9897,7 +9899,7 @@
     method public void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public void setWebViewClient(android.webkit.WebViewClient);
-    method public void setWebViewRendererClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRendererClient);
+    method public void setWebViewRenderProcessClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRenderProcessClient);
     method public boolean showFindDialog(String, boolean);
     method public void stopLoading();
     method public boolean zoomBy(float);
@@ -9979,10 +9981,6 @@
     field public final android.content.pm.Signature[] signatures;
   }
 
-  public abstract class WebViewRenderer {
-    ctor public WebViewRenderer();
-  }
-
   public final class WebViewUpdateService {
     method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
     method public static String getCurrentWebViewPackageName();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7e04469..18d0ec0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -60,6 +60,14 @@
 
 }
 
+package android.content.pm {
+
+  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
+    method @Deprecated public void setEnableRollback();
+  }
+
+}
+
 package android.location {
 
   public class LocationManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index b0e8df8..97f5ffe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -512,24 +512,19 @@
 
   public final class RoleManager {
     method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
     field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
   }
 
-  public interface RoleManagerCallback {
-    method public void onFailure();
-    method public void onSuccess();
-  }
-
 }
 
 package android.app.usage {
@@ -2007,6 +2002,7 @@
   }
 
   public final class DeviceConfig {
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(String, String, boolean);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(String, String, float);
@@ -2014,15 +2010,19 @@
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(String, String, long);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String);
-    method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
+    method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+    method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
     method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
   }
 
+  public static interface DeviceConfig.OnPropertiesChangedListener {
+    method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
+  }
+
   public static interface DeviceConfig.OnPropertyChangedListener {
-    method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
     method public void onPropertyChanged(String, String, String);
   }
 
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index e5f6223..e85f132 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -38,7 +38,10 @@
 
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
-using android::idmap2::PoliciesToBitmask;
+using android::idmap2::kPolicyProduct;
+using android::idmap2::kPolicyPublic;
+using android::idmap2::kPolicySystem;
+using android::idmap2::kPolicyVendor;
 using android::idmap2::PolicyBitmask;
 using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
@@ -87,20 +90,22 @@
   return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
 }
 
-PolicyBitmask PolicyForPath(const std::string& apk_path) {
-  static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
-      {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
-      {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
-      {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
+  static const std::vector<std::pair<std::string, std::string>> values = {
+      {"/product/", kPolicyProduct},
+      {"/system/", kPolicySystem},
+      {"/vendor/", kPolicyVendor},
   };
 
+  std::vector<std::string> fulfilled_policies = {kPolicyPublic};
   for (auto const& pair : values) {
     if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
-      return pair.second | PolicyFlags::POLICY_PUBLIC;
+      fulfilled_policies.emplace_back(pair.second);
+      break;
     }
   }
 
-  return PolicyFlags::POLICY_PUBLIC;
+  return fulfilled_policies;
 }
 
 }  // namespace
@@ -161,21 +166,17 @@
       continue;
     }
 
-    PolicyBitmask fulfilled_policies;
+    std::vector<std::string> fulfilled_policies;
     if (!override_policies.empty()) {
-      auto conv_result = PoliciesToBitmask(override_policies);
-      if (conv_result) {
-        fulfilled_policies = *conv_result;
-      } else {
-        out_error << "error: " << conv_result.GetErrorMessage() << std::endl;
-        return false;
-      }
+      fulfilled_policies = override_policies;
     } else {
-      fulfilled_policies = PolicyForPath(path);
+      fulfilled_policies = PoliciesForPath(path);
     }
 
     bool ignore_overlayable = false;
-    if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+    if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) !=
+            fulfilled_policies.end() &&
+        !VendorIsQOrLater()) {
       // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
       // restrictions on this overlay because the pre-Q platform has no understanding of
       // overlayable.
@@ -185,7 +186,7 @@
     std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
 
     // Sort the static overlays in ascending priority order
-    InputOverlay input{path, idmap_path, overlay_info->priority, override_policies,
+    InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_policies,
                        ignore_overlayable};
     interesting_apks.insert(
         std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
@@ -211,8 +212,8 @@
       }
 
       for (const std::string& policy : overlay.policies) {
-        verify_args.emplace_back("--policy");
-        verify_args.emplace_back(policy);
+        create_args.emplace_back("--policy");
+        create_args.emplace_back(policy);
       }
 
       if (!Create(create_args, out_error)) {
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
index 911d3f2..cd76b84 100644
--- a/cmds/idmap2/include/idmap2/Policies.h
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -27,13 +27,21 @@
 
 namespace android::idmap2 {
 
+constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyProduct = "product";
+constexpr const char* kPolicySystem = "system";
+constexpr const char* kPolicyVendor = "vendor";
+constexpr const char* kPolicySignature = "signature";
+
 using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
 using PolicyBitmask = uint32_t;
 
-// Parses a the string representation of a set of policies into a bitmask. The format of the string
-// is the same as for the <policy> element.
+// Parses the string representations of policies into a bitmask.
 Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies);
 
+// Retrieves the string representations of policies in the bitmask.
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask);
+
 }  // namespace android::idmap2
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 889d731..a7d180c 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -285,24 +285,58 @@
   return std::move(idmap);
 }
 
-bool CheckOverlayable(const LoadedPackage& target_package,
-                      const utils::OverlayManifestInfo& overlay_info,
-                      const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
+std::string ConcatPolicies(const std::vector<std::string>& policies) {
+  std::string message;
+  for (const std::string& policy : policies) {
+    if (message.empty()) {
+      message.append(policy);
+    } else {
+      message.append(policy);
+      message.append("|");
+    }
+  }
+
+  return message;
+}
+
+Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
+                              const utils::OverlayManifestInfo& overlay_info,
+                              const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
+  static constexpr const PolicyBitmask sDefaultPolicies =
+      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
+      PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
+
+  // If the resource does not have an overlayable definition, allow the resource to be overlaid if
+  // the overlay is preinstalled or signed with the same signature as the target.
+  if (!target_package.DefinesOverlayable()) {
+    return (sDefaultPolicies & fulfilled_policies) != 0
+               ? Result<Unit>({})
+               : Error(
+                     "overlay must be preinstalled or signed with the same signature as the "
+                     "target");
+  }
+
   const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
   if (overlayable_info == nullptr) {
-    // If the resource does not have an overlayable definition, allow the resource to be overlaid.
-    // Once overlayable enforcement is turned on, this check will return false.
-    return !target_package.DefinesOverlayable();
+    // Do not allow non-overlayable resources to be overlaid.
+    return Error("resource has no overlayable declaration");
   }
 
   if (overlay_info.target_name != overlayable_info->name) {
     // If the overlay supplies a target overlayable name, the resource must belong to the
     // overlayable defined with the specified name to be overlaid.
-    return false;
+    return Error("<overlay> android:targetName '%s' does not match overlayable name '%s'",
+                 overlay_info.target_name.c_str(), overlayable_info->name.c_str());
   }
 
   // Enforce policy restrictions if the resource is declared as overlayable.
-  return (overlayable_info->policy_flags & fulfilled_policies) != 0;
+  if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
+    return Error("overlay with policies '%s' does not fulfill any overlayable policies '%s'",
+                 ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
+                 ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+  }
+
+  return Result<Unit>({});
 }
 
 std::unique_ptr<const Idmap> Idmap::FromApkAssets(
@@ -418,16 +452,26 @@
       continue;
     }
 
-    if (enforce_overlayable &&
-        !CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid)) {
-      LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
-                   << full_name << "\"" << std::endl;
-      continue;
+    if (!enforce_overlayable) {
+      Result<Unit> success =
+          CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid);
+      if (!success) {
+        LOG(WARNING) << "overlay \"" << overlay_apk_path
+                     << "\" is not allowed to overlay resource \"" << full_name
+                     << "\": " << success.GetErrorMessage();
+        continue;
+      }
     }
 
     matching_resources.Add(target_resid, overlay_resid);
   }
 
+  if (matching_resources.Map().empty()) {
+    out_error << "overlay \"" << overlay_apk_path << "\" does not successfully overlay any resource"
+              << std::endl;
+    return nullptr;
+  }
+
   // encode idmap data
   std::unique_ptr<IdmapData> data(new IdmapData());
   const auto types_end = matching_resources.Map().cend();
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
index c6ba87d..7c45556 100644
--- a/cmds/idmap2/libidmap2/Policies.cpp
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -30,12 +30,13 @@
 namespace {
 
 const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
-    {"public", PolicyFlags::POLICY_PUBLIC},
-    {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
-    {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
-    {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
-    {"signature", PolicyFlags::POLICY_SIGNATURE},
+    {kPolicyPublic, PolicyFlags::POLICY_PUBLIC},
+    {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION},
+    {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION},
+    {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION},
+    {kPolicySignature, PolicyFlags::POLICY_SIGNATURE},
 };
+
 }  // namespace
 
 Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies) {
@@ -52,4 +53,29 @@
   return Result<PolicyBitmask>(bitmask);
 }
 
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
+  std::vector<std::string> policies;
+  if ((bitmask & PolicyFlags::POLICY_PUBLIC) != 0) {
+    policies.emplace_back(kPolicyPublic);
+  }
+
+  if ((bitmask & PolicyFlags::POLICY_PRODUCT_PARTITION) != 0) {
+    policies.emplace_back(kPolicyProduct);
+  }
+
+  if ((bitmask & PolicyFlags::POLICY_SYSTEM_PARTITION) != 0) {
+    policies.emplace_back(kPolicySystem);
+  }
+
+  if ((bitmask & PolicyFlags::POLICY_VENDOR_PARTITION) != 0) {
+    policies.emplace_back(kPolicyVendor);
+  }
+
+  if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) {
+    policies.emplace_back(kPolicySignature);
+  }
+
+  return policies;
+}
+
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index bbfbad9..8d65428 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -173,20 +173,27 @@
   ASSERT_THAT(idmap, IsNull());
 }
 
-TEST(IdmapTests, CreateIdmapFromApkAssets) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+void CreateIdmap(const StringPiece& target_apk_path, const StringPiece& overlay_apk_path,
+                 const PolicyBitmask& fulfilled_policies, bool enforce_overlayable,
+                 std::unique_ptr<const Idmap>* out_idmap) {
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path.to_string());
   ASSERT_THAT(target_apk, NotNull());
 
-  const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path.to_string());
   ASSERT_THAT(overlay_apk, NotNull());
 
   std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
+  *out_idmap =
+      Idmap::FromApkAssets(target_apk_path.to_string(), *target_apk, overlay_apk_path.to_string(),
+                           *overlay_apk, fulfilled_policies, enforce_overlayable, error);
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssets) {
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ true, &idmap);
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
@@ -226,19 +233,12 @@
 
 // Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
 TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
-                           /* enforce_overlayable */ true, error);
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  std::string overlay_apk_path = GetTestDataPath() + "/system-overlay/system-overlay.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path,
+              PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ true, &idmap);
   ASSERT_THAT(idmap, NotNull());
 
   const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -263,21 +263,12 @@
 }
 
 TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignature) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() +
-                                     "/signature-overlay/signature-overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE;
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           policy_flags, /* enforce_overlayable */ true, error);
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  std::string overlay_apk_path = GetTestDataPath() + "/signature-overlay/signature-overlay.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path,
+              PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE,
+              /* enforce_overlayable */ true, &idmap);
   ASSERT_THAT(idmap, NotNull());
 
   const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -298,52 +289,15 @@
   ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/policy_signature
 }
 
-TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignatureNotFulfilled) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() +
-                                     "/signature-overlay/signature-overlay.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC;
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           policy_flags, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
-
-  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
-  ASSERT_EQ(dataBlocks.size(), 1U);
-
-  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
-
-  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
-  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 0U);
-
-  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
-  ASSERT_EQ(types.size(), 0U);  // can't overlay, so contains nothing
-}
-
 // Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
 TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() +
-                                     "/system-overlay-invalid/system-overlay-invalid.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
-                           /* enforce_overlayable */ true, error);
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  std::string overlay_apk_path =
+      GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path,
+              PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ true, &idmap);
   ASSERT_THAT(idmap, NotNull());
 
   const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -369,20 +323,13 @@
 
 // Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled.
 TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() +
-                                     "/system-overlay-invalid/system-overlay-invalid.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
-                           /* enforce_overlayable */ false, error);
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+  std::string overlay_apk_path =
+      GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path,
+              PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ false, &idmap);
   ASSERT_THAT(idmap, NotNull());
 
   const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -409,63 +356,13 @@
   ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_system_vendor
 }
 
-// The resources of APKs that do not include an overlayable declaration should not restrict what
-// resources can be overlaid.
-TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayable) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() +
-                                     "/system-overlay-invalid/system-overlay-invalid.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
-
-  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
-  ASSERT_EQ(dataBlocks.size(), 1U);
-
-  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
-
-  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
-  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
-
-  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
-  ASSERT_EQ(types.size(), 1U);
-
-  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
-  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
-  ASSERT_EQ(types[0]->GetEntryCount(), 7U);
-  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
-  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
-  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
-  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
-  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_public
-  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/string/policy_signature
-  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system
-  ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_system_vendor
-}
-
-// The resources of APKs that do not include an overlayable declaration should not restrict what
-// resources can be overlaid.
+// Overlays that do not specify a target <overlayable> can overlay resources defined as overlayable.
 TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
-  const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
-  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
-  ASSERT_THAT(target_apk, NotNull());
-
-  const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay-no-name.apk");
-  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-  ASSERT_THAT(overlay_apk, NotNull());
-
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+  std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ false, &idmap);
   ASSERT_THAT(idmap, NotNull());
 
   const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -483,16 +380,81 @@
   ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
   ASSERT_EQ(types[0]->GetEntryCount(), 1U);
   ASSERT_EQ(types[0]->GetEntryOffset(), 0U);
-  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/int1
 
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
   ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
-  ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
-  ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
-  ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
-  ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
+  ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);   // string/str1
+  ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);  // string/str2
+  ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);   // string/str3
+  ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);   // string/str4
+}
+
+// Overlays that are not pre-installed and are not signed with the same signature as the target
+// cannot overlay packages that have not defined overlayable resources.
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPoliciesPublicFail) {
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+  std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk";
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, IsNull());
+}
+
+// Overlays that are pre-installed or are signed with the same signature as the target can overlay
+// packages that have not defined overlayable resources.
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPolicies) {
+  std::unique_ptr<const Idmap> idmap;
+  std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+  std::string overlay_apk_path =
+      GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+
+  auto CheckEntries = [&]() -> void {
+    const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+    ASSERT_EQ(dataBlocks.size(), 1U);
+
+    const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+    ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+    ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+    const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+    ASSERT_EQ(types.size(), 1U);
+
+    ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+    ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+    ASSERT_EQ(types[0]->GetEntryCount(), 7U);
+    ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+    ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
+    ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
+    ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
+    ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_public
+    ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/string/policy_signature
+    ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system
+    ASSERT_EQ(types[0]->GetEntry(6), 0x0006U);  // string/policy_system_vendor
+  };
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SIGNATURE,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PRODUCT_PARTITION,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SYSTEM_PARTITION,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
+
+  CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_VENDOR_PARTITION,
+              /* enforce_overlayable */ true, &idmap);
+  ASSERT_THAT(idmap, NotNull());
+  CheckEntries();
 }
 
 TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
diff --git a/cmds/idmap2/tests/data/overlay/build b/cmds/idmap2/tests/data/overlay/build
index e879f44..68b9f50 100755
--- a/cmds/idmap2/tests/data/overlay/build
+++ b/cmds/idmap2/tests/data/overlay/build
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FRAMEWORK_RES_APK="${ANDROID_BUILD_TOP}/out/target/common/obj/APPS/framework-res_intermediates/package-export.apk"
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
 
 aapt2 compile --dir res -o compiled.flata
 
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index 7d23c09..6425190 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 03806fa..a8a34d2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3177,6 +3177,7 @@
      * Returns the bubble metadata that will be used to display app content in a floating window
      * over the existing foreground activity.
      */
+    @Nullable
     public BubbleMetadata getBubbleMetadata() {
         return mBubbleMetadata;
     }
@@ -3568,7 +3569,7 @@
          * collapsed state, the bubble intent will be invoked and displayed.</b>
          */
         @NonNull
-        public Builder setBubbleMetadata(BubbleMetadata data) {
+        public Builder setBubbleMetadata(@Nullable BubbleMetadata data) {
             mN.mBubbleMetadata = data;
             return this;
         }
@@ -8562,6 +8563,7 @@
         /**
          * @return the pending intent used to populate the floating window for this bubble.
          */
+        @NonNull
         public PendingIntent getIntent() {
             return mPendingIntent;
         }
@@ -8569,6 +8571,7 @@
         /**
          * @return the pending intent to send when the bubble is dismissed by a user, if one exists.
          */
+        @Nullable
         public PendingIntent getDeleteIntent() {
             return mDeleteIntent;
         }
@@ -8583,9 +8586,11 @@
         public CharSequence getTitle() {
             return "";
         }
+
         /**
          * @return the icon that will be displayed for this bubble when it is collapsed.
          */
+        @NonNull
         public Icon getIcon() {
             return mIcon;
         }
@@ -8654,7 +8659,7 @@
         /**
          * Builder to construct a {@link BubbleMetadata} object.
          */
-        public static class Builder {
+        public static final class Builder {
 
             private PendingIntent mPendingIntent;
             private Icon mIcon;
@@ -8672,7 +8677,8 @@
              * Sets the intent that will be used when the bubble is expanded. This will display the
              * app content in a floating window over the existing foreground activity.
              */
-            public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+            @NonNull
+            public BubbleMetadata.Builder setIntent(@NonNull PendingIntent intent) {
                 if (intent == null) {
                     throw new IllegalArgumentException("Bubble requires non-null pending intent");
                 }
@@ -8700,7 +8706,8 @@
              * If your app produces multiple bubbles, the image should be unique for each of them.
              * </p>
              */
-            public BubbleMetadata.Builder setIcon(Icon icon) {
+            @NonNull
+            public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
                 if (icon == null) {
                     throw new IllegalArgumentException("Bubbles require non-null icon");
                 }
@@ -8713,6 +8720,7 @@
              * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
              * enough space on the screen or if the provided height is too small to be useful.
              */
+            @NonNull
             public BubbleMetadata.Builder setDesiredHeight(int height) {
                 mDesiredHeight = Math.max(height, 0);
                 return this;
@@ -8729,6 +8737,7 @@
              * <p>Generally this flag should only be set if the user has performed an action to
              * request or create a bubble.</p>
              */
+            @NonNull
             public BubbleMetadata.Builder setAutoExpandBubble(boolean shouldExpand) {
                 setFlag(FLAG_AUTO_EXPAND_BUBBLE, shouldExpand);
                 return this;
@@ -8745,6 +8754,7 @@
              * <p>Generally this flag should only be set if the user has performed an action to
              * request or create a bubble.</p>
              */
+            @NonNull
             public BubbleMetadata.Builder setSuppressInitialNotification(
                     boolean shouldSupressNotif) {
                 setFlag(FLAG_SUPPRESS_INITIAL_NOTIFICATION, shouldSupressNotif);
@@ -8754,7 +8764,8 @@
             /**
              * Sets an optional intent to send when this bubble is explicitly removed by the user.
              */
-            public BubbleMetadata.Builder setDeleteIntent(PendingIntent deleteIntent) {
+            @NonNull
+            public BubbleMetadata.Builder setDeleteIntent(@Nullable PendingIntent deleteIntent) {
                 mDeleteIntent = deleteIntent;
                 return this;
             }
@@ -8764,6 +8775,7 @@
              * <p>Will throw {@link IllegalStateException} if required fields have not been set
              * on this builder.</p>
              */
+            @NonNull
             public BubbleMetadata build() {
                 if (mPendingIntent == null) {
                     throw new IllegalStateException("Must supply pending intent to bubble");
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 095d014..7cdd227 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -84,7 +84,6 @@
 import android.service.restrictions.RestrictionsReceiver;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -2210,7 +2209,7 @@
             PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SetPrivateDnsModeResultConstants {}
+    public @interface PrivateDnsModeErrorCodes {}
 
     /**
      * Activity action: Starts the administrator to get the mode for the provisioning.
@@ -10450,13 +10449,41 @@
     }
 
     /**
-     * Sets the global Private DNS mode and host to be used.
+     * Sets the global Private DNS mode to opportunistic.
      * May only be called by the device owner.
      *
-     * <p>Note that in case a Private DNS resolver is specified, the method is blocking as it
-     * will perform a connectivity check to the resolver, to ensure it is valid. Because of that,
-     * the method should not be called on any thread that relates to user interaction, such as the
-     * UI thread.
+     * <p>In this mode, the DNS subsystem will attempt a TLS handshake to the network-supplied
+     * resolver prior to attempting name resolution in cleartext.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+     *
+     * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully, or
+     *         {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set.
+     *
+     * @throws SecurityException if the caller is not the device owner.
+     */
+    public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeOpportunistic(
+            @NonNull ComponentName admin) {
+        throwIfParentInstance("setGlobalPrivateDnsModeOpportunistic");
+
+        if (mService == null) {
+            return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+        }
+
+        try {
+            return mService.setGlobalPrivateDns(admin, PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the global Private DNS host to be used.
+     * May only be called by the device owner.
+     *
+     * <p>Note that the method is blocking as it will perform a connectivity check to the resolver,
+     * to ensure it is valid. Because of that, the method should not be called on any thread that
+     * relates to user interaction, such as the UI thread.
      *
      * <p>In case a VPN is used in conjunction with Private DNS resolver, the Private DNS resolver
      * must be reachable both from within and outside the VPN. Otherwise, the device may lose
@@ -10464,41 +10491,35 @@
      * VPN.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
-     * @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
-     *             {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
-     *             Since the opportunistic mode defaults to ordinary DNS lookups, the
-     *             option to turn it completely off is not available, so this method
-     *             may not be called with {@code PRIVATE_DNS_MODE_OFF}.
-     * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
-     *                       {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
-     *                       null otherwise.
+     * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858).
      *
-     * @return One of the values in {@link SetPrivateDnsModeResultConstants}.
+     * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully,
+     *         {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set or
+     *         {@code PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING} if the specified host does not
+     *         implement RFC7858.
      *
-     * @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
-     * provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
-     * specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
-     * not look like a valid hostname, or if the mode specified is not one of the two valid modes.
+     * @throws IllegalArgumentException if the {@code privateDnsHost} is not a valid hostname.
      *
      * @throws SecurityException if the caller is not the device owner.
      */
-    public int setGlobalPrivateDns(@NonNull ComponentName admin,
-            @PrivateDnsMode int mode, @Nullable String privateDnsHost) {
-        throwIfParentInstance("setGlobalPrivateDns");
+    @WorkerThread public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeSpecifiedHost(
+            @NonNull ComponentName admin, @NonNull String privateDnsHost) {
+        throwIfParentInstance("setGlobalPrivateDnsModeSpecifiedHost");
+        Preconditions.checkNotNull(privateDnsHost, "dns resolver is null");
 
         if (mService == null) {
             return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
         }
 
-        if (mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME && !TextUtils.isEmpty(privateDnsHost)
-                && NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+        if (NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
             if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
                 return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
             }
         }
 
         try {
-            return mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
+            return mService.setGlobalPrivateDns(
+                    admin, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, privateDnsHost);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/role/IRoleController.aidl b/core/java/android/app/role/IRoleController.aidl
index e8f6ce2..a472eac 100644
--- a/core/java/android/app/role/IRoleController.aidl
+++ b/core/java/android/app/role/IRoleController.aidl
@@ -16,7 +16,6 @@
 
 package android.app.role;
 
-import android.app.role.IRoleManagerCallback;
 import android.os.RemoteCallback;
 
 /**
@@ -24,20 +23,20 @@
  */
 oneway interface IRoleController {
 
-    void onGrantDefaultRoles(in IRoleManagerCallback callback);
+    void grantDefaultRoles(in RemoteCallback callback);
 
     void onAddRoleHolder(in String roleName, in String packageName, int flags,
-                         in IRoleManagerCallback callback);
+            in RemoteCallback callback);
 
     void onRemoveRoleHolder(in String roleName, in String packageName, int flags,
-                            in IRoleManagerCallback callback);
+            in RemoteCallback callback);
 
-    void onClearRoleHolders(in String roleName, int flags, in IRoleManagerCallback callback);
+    void onClearRoleHolders(in String roleName, int flags, in RemoteCallback callback);
 
     void onSmsKillSwitchToggled(boolean enabled);
 
     void isApplicationQualifiedForRole(in String roleName, in String packageName,
-                                       in RemoteCallback callback);
+            in RemoteCallback callback);
 
     void isRoleVisible(in String roleName, in RemoteCallback callback);
 }
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 76dbf7e..d8cea28 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -17,8 +17,8 @@
 package android.app.role;
 
 import android.app.role.IOnRoleHoldersChangedListener;
-import android.app.role.IRoleManagerCallback;
 import android.os.Bundle;
+import android.os.RemoteCallback;
 import android.telephony.IFinancialSmsCallback;
 
 /**
@@ -33,13 +33,13 @@
     List<String> getRoleHoldersAsUser(in String roleName, int userId);
 
     void addRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
-            in IRoleManagerCallback callback);
+            in RemoteCallback callback);
 
     void removeRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
-            in IRoleManagerCallback callback);
+            in RemoteCallback callback);
 
     void clearRoleHoldersAsUser(in String roleName, int flags, int userId,
-            in IRoleManagerCallback callback);
+            in RemoteCallback callback);
 
     void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
 
@@ -55,6 +55,7 @@
     List<String> getHeldRolesFromController(in String packageName);
 
     String getDefaultSmsPackage(int userId);
+
     /**
      * Get filtered SMS messages for financial app.
      */
diff --git a/core/java/android/app/role/IRoleManagerCallback.aidl b/core/java/android/app/role/IRoleManagerCallback.aidl
deleted file mode 100644
index c0f8eea..0000000
--- a/core/java/android/app/role/IRoleManagerCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.role;
-
-/**
- * @hide
- */
-oneway interface IRoleManagerCallback {
-
-    void onSuccess();
-
-    void onFailure();
-}
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 2edc526..e96c9a5 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -52,11 +52,6 @@
 
     private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
 
-    /**
-     * The key for retrieving the result from a bundle.
-     */
-    public static final String KEY_RESULT = "android.app.role.RoleControllerManager.key.RESULT";
-
     private static final Object sRemoteServicesLock = new Object();
     /**
      * Global remote services (per user) used by all {@link RoleControllerManager managers}.
@@ -90,35 +85,37 @@
     }
 
     /**
-     * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback)
+     * @see RoleControllerService#onGrantDefaultRoles()
      */
-    public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) {
-        mRemoteService.scheduleRequest(new OnGrantDefaultRolesRequest(mRemoteService, callback));
+    public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> callback) {
+        mRemoteService.scheduleRequest(new GrantDefaultRolesRequest(mRemoteService, executor,
+                callback));
     }
 
     /**
-     * @see RoleControllerService#onAddRoleHolder(String, String, int, RoleManagerCallback)
+     * @see RoleControllerService#onAddRoleHolder(String, String, int)
      */
     public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
         mRemoteService.scheduleRequest(new OnAddRoleHolderRequest(mRemoteService, roleName,
                 packageName, flags, callback));
     }
 
     /**
-     * @see RoleControllerService#onRemoveRoleHolder(String, String, int, RoleManagerCallback)
+     * @see RoleControllerService#onRemoveRoleHolder(String, String, int)
      */
     public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
         mRemoteService.scheduleRequest(new OnRemoveRoleHolderRequest(mRemoteService, roleName,
                 packageName, flags, callback));
     }
 
     /**
-     * @see RoleControllerService#onClearRoleHolders(String, int, RoleManagerCallback)
+     * @see RoleControllerService#onClearRoleHolders(String, int)
      */
     public void onClearRoleHolders(@NonNull String roleName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
         mRemoteService.scheduleRequest(new OnClearRoleHoldersRequest(mRemoteService, roleName,
                 flags, callback));
     }
@@ -210,68 +207,55 @@
     }
 
     /**
-     * Request for {@link #onGrantDefaultRoles(IRoleManagerCallback)}.
+     * Request for {@link #grantDefaultRoles(Executor, Consumer)}.
      */
-    private static final class OnGrantDefaultRolesRequest
+    private static final class GrantDefaultRolesRequest
             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
 
         @NonNull
-        private final IRoleManagerCallback mCallback;
+        private final Executor mExecutor;
+        @NonNull
+        private final Consumer<Boolean> mCallback;
 
         @NonNull
-        private final IRoleManagerCallback mRemoteCallback;
+        private final RemoteCallback mRemoteCallback;
 
-        private OnGrantDefaultRolesRequest(@NonNull RemoteService service,
-                @NonNull IRoleManagerCallback callback) {
+        private GrantDefaultRolesRequest(@NonNull RemoteService service,
+                @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
             super(service);
 
+            mExecutor = executor;
             mCallback = callback;
 
-            mRemoteCallback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
+            mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    boolean successful = result != null;
+                    mCallback.accept(successful);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    finish();
                 }
-                @Override
-                public void onFailure() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
-                }
-            };
+            }));
         }
 
         @Override
         protected void onTimeout(@NonNull RemoteService remoteService) {
-            try {
-                mCallback.onFailure();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
-            }
+            mExecutor.execute(() -> mCallback.accept(false));
         }
 
         @Override
         public void run() {
             try {
-                getService().getServiceInterface().onGrantDefaultRoles(mRemoteCallback);
+                getService().getServiceInterface().grantDefaultRoles(mRemoteCallback);
             } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onGrantDefaultRoles()", e);
+                Log.e(LOG_TAG, "Error calling grantDefaultRoles()", e);
             }
         }
     }
 
     /**
-     * Request for {@link #onAddRoleHolder(String, String, int, IRoleManagerCallback)}.
+     * Request for {@link #onAddRoleHolder(String, String, int, RemoteCallback)}.
      */
     private static final class OnAddRoleHolderRequest
             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -283,14 +267,14 @@
         @RoleManager.ManageHoldersFlags
         private final int mFlags;
         @NonNull
-        private final IRoleManagerCallback mCallback;
+        private final RemoteCallback mCallback;
 
         @NonNull
-        private final IRoleManagerCallback mRemoteCallback;
+        private final RemoteCallback mRemoteCallback;
 
         private OnAddRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
                 @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
-                @NonNull IRoleManagerCallback callback) {
+                @NonNull RemoteCallback callback) {
             super(service);
 
             mRoleName = roleName;
@@ -298,37 +282,20 @@
             mFlags = flags;
             mCallback = callback;
 
-            mRemoteCallback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
+            mRemoteCallback = new RemoteCallback(result -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallback.sendResult(result);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    finish();
                 }
-                @Override
-                public void onFailure() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
-                }
-            };
+            });
         }
 
         @Override
         protected void onTimeout(@NonNull RemoteService remoteService) {
-            try {
-                mCallback.onFailure();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
-            }
+            mCallback.sendResult(null);
         }
 
         @Override
@@ -343,7 +310,7 @@
     }
 
     /**
-     * Request for {@link #onRemoveRoleHolder(String, String, int, IRoleManagerCallback)}.
+     * Request for {@link #onRemoveRoleHolder(String, String, int, RemoteCallback)}.
      */
     private static final class OnRemoveRoleHolderRequest
             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -355,14 +322,14 @@
         @RoleManager.ManageHoldersFlags
         private final int mFlags;
         @NonNull
-        private final IRoleManagerCallback mCallback;
+        private final RemoteCallback mCallback;
 
         @NonNull
-        private final IRoleManagerCallback mRemoteCallback;
+        private final RemoteCallback mRemoteCallback;
 
         private OnRemoveRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
                 @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
-                @NonNull IRoleManagerCallback callback) {
+                @NonNull RemoteCallback callback) {
             super(service);
 
             mRoleName = roleName;
@@ -370,37 +337,20 @@
             mFlags = flags;
             mCallback = callback;
 
-            mRemoteCallback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
+            mRemoteCallback = new RemoteCallback(result -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallback.sendResult(result);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    finish();
                 }
-                @Override
-                public void onFailure() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
-                }
-            };
+            });
         }
 
         @Override
         protected void onTimeout(@NonNull RemoteService remoteService) {
-            try {
-                mCallback.onFailure();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
-            }
+            mCallback.sendResult(null);
         }
 
         @Override
@@ -415,7 +365,7 @@
     }
 
     /**
-     * Request for {@link #onClearRoleHolders(String, int, IRoleManagerCallback)}.
+     * Request for {@link #onClearRoleHolders(String, int, RemoteCallback)}.
      */
     private static final class OnClearRoleHoldersRequest
             extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -425,50 +375,33 @@
         @RoleManager.ManageHoldersFlags
         private final int mFlags;
         @NonNull
-        private final IRoleManagerCallback mCallback;
+        private final RemoteCallback mCallback;
 
         @NonNull
-        private final IRoleManagerCallback mRemoteCallback;
+        private final RemoteCallback mRemoteCallback;
 
         private OnClearRoleHoldersRequest(@NonNull RemoteService service, @NonNull String roleName,
-                @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+                @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
             super(service);
 
             mRoleName = roleName;
             mFlags = flags;
             mCallback = callback;
 
-            mRemoteCallback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
+            mRemoteCallback = new RemoteCallback(result -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mCallback.sendResult(result);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                    finish();
                 }
-                @Override
-                public void onFailure() throws RemoteException {
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        mCallback.onSuccess();
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                        finish();
-                    }
-                }
-            };
+            });
         }
 
         @Override
         protected void onTimeout(@NonNull RemoteService remoteService) {
-            try {
-                mCallback.onFailure();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
-            }
+            mCallback.sendResult(null);
         }
 
         @Override
@@ -535,7 +468,7 @@
             mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
                 long token = Binder.clearCallingIdentity();
                 try {
-                    boolean qualified = result != null && result.getBoolean(KEY_RESULT);
+                    boolean qualified = result != null;
                     mCallback.accept(qualified);
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -587,7 +520,7 @@
             mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
                 long token = Binder.clearCallingIdentity();
                 try {
-                    boolean visible = result != null && result.getBoolean(KEY_RESULT);
+                    boolean visible = result != null;
                     mCallback.accept(visible);
                 } finally {
                     Binder.restoreCallingIdentity(token);
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 47be385..312761d 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -20,16 +20,20 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteCallback;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.Log;
 
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.util.concurrent.Executor;
 
@@ -45,59 +49,102 @@
 @SystemApi
 public abstract class RoleControllerService extends Service {
 
-    private static final String LOG_TAG = RoleControllerService.class.getSimpleName();
-
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
     public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
 
+    private HandlerThread mWorkerThread;
+    private Handler mWorkerHandler;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mWorkerThread = new HandlerThread(RoleControllerService.class.getSimpleName());
+        mWorkerThread.start();
+        mWorkerHandler = new Handler(mWorkerThread.getLooper());
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        mWorkerThread.quitSafely();
+    }
+
     @Nullable
     @Override
     public final IBinder onBind(@Nullable Intent intent) {
         return new IRoleController.Stub() {
 
             @Override
-            public void onGrantDefaultRoles(IRoleManagerCallback callback) {
+            public void grantDefaultRoles(RemoteCallback callback) {
+                enforceCallerSystemUid("grantDefaultRoles");
+
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onGrantDefaultRoles(new RoleManagerCallbackDelegate(
+
+                mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+                        RoleControllerService::grantDefaultRoles, RoleControllerService.this,
                         callback));
             }
 
             @Override
             public void onAddRoleHolder(String roleName, String packageName, int flags,
-                    IRoleManagerCallback callback) {
+                    RemoteCallback callback) {
+                enforceCallerSystemUid("onAddRoleHolder");
+
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onAddRoleHolder(roleName, packageName, flags,
-                        new RoleManagerCallbackDelegate(callback));
+
+                mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+                        RoleControllerService::onAddRoleHolder, RoleControllerService.this,
+                        roleName, packageName, flags, callback));
             }
 
             @Override
             public void onRemoveRoleHolder(String roleName, String packageName, int flags,
-                    IRoleManagerCallback callback) {
+                    RemoteCallback callback) {
+                enforceCallerSystemUid("onRemoveRoleHolder");
+
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onRemoveRoleHolder(roleName, packageName, flags,
-                        new RoleManagerCallbackDelegate(callback));
+
+                mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+                        RoleControllerService::onRemoveRoleHolder, RoleControllerService.this,
+                        roleName, packageName, flags, callback));
             }
 
             @Override
-            public void onClearRoleHolders(String roleName, int flags,
-                    IRoleManagerCallback callback) {
+            public void onClearRoleHolders(String roleName, int flags, RemoteCallback callback) {
+                enforceCallerSystemUid("onClearRoleHolders");
+
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onClearRoleHolders(roleName, flags,
-                        new RoleManagerCallbackDelegate(callback));
+
+                mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+                        RoleControllerService::onClearRoleHolders, RoleControllerService.this,
+                        roleName, flags, callback));
             }
 
             @Override
-            public void onSmsKillSwitchToggled(boolean smsRestrictionEnabled) {
-                RoleControllerService.this.onSmsKillSwitchToggled(smsRestrictionEnabled);
+            public void onSmsKillSwitchToggled(boolean enabled) {
+                enforceCallerSystemUid("onSmsKillSwitchToggled");
+
+                mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+                        RoleControllerService::onSmsKillSwitchToggled, RoleControllerService.this,
+                        enabled));
+            }
+
+            private void enforceCallerSystemUid(@NonNull String methodName) {
+                if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                    throw new SecurityException("Only the system process can call " + methodName
+                            + "()");
+                }
             }
 
             @Override
@@ -111,9 +158,7 @@
                 Preconditions.checkNotNull(callback, "callback cannot be null");
 
                 boolean qualified = onIsApplicationQualifiedForRole(roleName, packageName);
-                Bundle result = new Bundle();
-                result.putBoolean(RoleControllerManager.KEY_RESULT, qualified);
-                callback.sendResult(result);
+                callback.sendResult(qualified ? Bundle.EMPTY : null);
             }
 
             @Override
@@ -124,22 +169,44 @@
                 Preconditions.checkNotNull(callback, "callback cannot be null");
 
                 boolean visible = onIsRoleVisible(roleName);
-                Bundle result = new Bundle();
-                result.putBoolean(RoleControllerManager.KEY_RESULT, visible);
-                callback.sendResult(result);
+                callback.sendResult(visible ? Bundle.EMPTY : null);
             }
         };
     }
 
+    private void grantDefaultRoles(@NonNull RemoteCallback callback) {
+        boolean successful = onGrantDefaultRoles();
+        callback.sendResult(successful ? Bundle.EMPTY : null);
+    }
+
+    private void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+        boolean successful = onAddRoleHolder(roleName, packageName, flags);
+        callback.sendResult(successful ? Bundle.EMPTY : null);
+    }
+
+    private void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+        boolean successful = onRemoveRoleHolder(roleName, packageName, flags);
+        callback.sendResult(successful ? Bundle.EMPTY : null);
+    }
+
+    private void onClearRoleHolders(@NonNull String roleName,
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+        boolean successful = onClearRoleHolders(roleName, flags);
+        callback.sendResult(successful ? Bundle.EMPTY : null);
+    }
+
     /**
      * Called by system to grant default permissions and roles.
      * <p>
      * This is typically when creating a new user or upgrading either system or
      * permission controller package
      *
-     * @param callback the callback for whether this call is successful
+     * @return whether this call was successful
      */
-    public abstract void onGrantDefaultRoles(@NonNull RoleManagerCallback callback);
+    @WorkerThread
+    public abstract boolean onGrantDefaultRoles();
 
     /**
      * Add a specific application to the holders of a role. If the role is exclusive, the previous
@@ -151,13 +218,15 @@
      * @param roleName the name of the role to add the role holder for
      * @param packageName the package name of the application to add to the role holders
      * @param flags optional behavior flags
-     * @param callback the callback for whether this call is successful
+     *
+     * @return whether this call was successful
      *
      * @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
-     *      RoleManagerCallback)
+     *      RemoteCallback)
      */
-    public abstract void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+    @WorkerThread
+    public abstract boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+            @RoleManager.ManageHoldersFlags int flags);
 
     /**
      * Remove a specific application from the holders of a role.
@@ -165,33 +234,39 @@
      * @param roleName the name of the role to remove the role holder for
      * @param packageName the package name of the application to remove from the role holders
      * @param flags optional behavior flags
-     * @param callback the callback for whether this call is successful
+     *
+     * @return whether this call was successful
      *
      * @see RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, Executor,
-     *      RoleManagerCallback)
+     *      RemoteCallback)
      */
-    public abstract void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+    @WorkerThread
+    public abstract boolean onRemoveRoleHolder(@NonNull String roleName,
+            @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags);
 
     /**
      * Remove all holders of a role.
      *
      * @param roleName the name of the role to remove role holders for
      * @param flags optional behavior flags
-     * @param callback the callback for whether this call is successful
      *
-     * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor,
-     *      RoleManagerCallback)
+     * @return whether this call was successful
+     *
+     * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor, RemoteCallback)
      */
-    public abstract void onClearRoleHolders(@NonNull String roleName,
-            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+    @WorkerThread
+    public abstract boolean onClearRoleHolders(@NonNull String roleName,
+            @RoleManager.ManageHoldersFlags int flags);
 
     /**
      * Cleanup appop/permissions state in response to sms kill switch toggle
      *
      * @param enabled whether kill switch was turned on
+     *
+     * @hide
      */
     //STOPSHIP: remove this api before shipping a final version
+    @WorkerThread
     public abstract void onSmsKillSwitchToggled(boolean enabled);
 
     /**
@@ -213,31 +288,4 @@
      * @return whether the role should be visible to user
      */
     public abstract boolean onIsRoleVisible(@NonNull String roleName);
-
-    private static class RoleManagerCallbackDelegate implements RoleManagerCallback {
-
-        private IRoleManagerCallback mCallback;
-
-        RoleManagerCallbackDelegate(IRoleManagerCallback callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onSuccess() {
-            try {
-                mCallback.onSuccess();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onSuccess() callback");
-            }
-        }
-
-        @Override
-        public void onFailure() {
-            try {
-                mCallback.onFailure();
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Error calling onFailure() callback");
-            }
-        }
-    }
 }
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index a663498..d1f8ed2 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.os.Binder;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -42,6 +43,7 @@
 
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * This class provides information about and manages roles.
@@ -315,9 +317,9 @@
      *
      * @return a list of package names of the role holders, or an empty list if none.
      *
-     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
-     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
      *
      * @hide
      */
@@ -351,8 +353,8 @@
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
      *
      * @hide
      */
@@ -361,7 +363,7 @@
     @TestApi
     public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
             @ManageHoldersFlags int flags, @NonNull UserHandle user,
-            @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
+            @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
@@ -369,7 +371,7 @@
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
             mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
-                    new RoleManagerCallbackDelegate(executor, callback));
+                    createRemoteCallback(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -390,8 +392,8 @@
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
      *
      * @hide
      */
@@ -400,7 +402,7 @@
     @TestApi
     public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
             @ManageHoldersFlags int flags, @NonNull UserHandle user,
-            @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
+            @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
@@ -408,7 +410,7 @@
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
             mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
-                    new RoleManagerCallbackDelegate(executor, callback));
+                    createRemoteCallback(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -428,8 +430,8 @@
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
-     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
      *
      * @hide
      */
@@ -438,19 +440,33 @@
     @TestApi
     public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
             @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
-            @NonNull RoleManagerCallback callback) {
+            @NonNull Consumer<Boolean> callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
             mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
-                    new RoleManagerCallbackDelegate(executor, callback));
+                    createRemoteCallback(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    @NonNull
+    private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
+            @NonNull Consumer<Boolean> callback) {
+        return new RemoteCallback(result -> executor.execute(() -> {
+            boolean successful = result != null;
+            long token = Binder.clearCallingIdentity();
+            try {
+                callback.accept(successful);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }));
+    }
+
     /**
      * Add a listener to observe role holder changes
      * <p>
@@ -669,40 +685,6 @@
         }
     }
 
-    private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
-
-        @NonNull
-        private final Executor mExecutor;
-        @NonNull
-        private final RoleManagerCallback mCallback;
-
-        RoleManagerCallbackDelegate(@NonNull Executor executor,
-                @NonNull RoleManagerCallback callback) {
-            mExecutor = executor;
-            mCallback = callback;
-        }
-
-        @Override
-        public void onSuccess() {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(mCallback::onSuccess);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void onFailure() {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(mCallback::onFailure);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    }
-
     private static class OnRoleHoldersChangedListenerDelegate
             extends IOnRoleHoldersChangedListener.Stub {
 
diff --git a/core/java/android/app/role/RoleManagerCallback.java b/core/java/android/app/role/RoleManagerCallback.java
deleted file mode 100644
index a92ef32..0000000
--- a/core/java/android/app/role/RoleManagerCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.role;
-
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Callback for a {@link RoleManager} request.
- *
- * @hide
- */
-@SystemApi
-@TestApi
-public interface RoleManagerCallback {
-
-    /**
-     * Signals a success.
-     */
-    void onSuccess();
-
-    /**
-     * Signals a failure.
-     */
-    void onFailure();
-
-    /** @hide */
-    class Future extends CompletableFuture<Void> implements RoleManagerCallback {
-
-        @Override
-        public void onSuccess() {
-            complete(null);
-        }
-
-        @Override
-        public void onFailure() {
-            completeExceptionally(new RuntimeException());
-        }
-    }
-}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 0d0e466..b3d01fd 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -254,18 +254,32 @@
         public static final int FLUSH_TO_DISK = 25;
 
         /**
-         * An event type denoting that the device underwent a shutdown process.
+         * An event type denoting that the Android runtime underwent a shutdown process.
          * A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
          * services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
          * {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
+         *
+         * <p>The DEVICE_SHUTDOWN timestamp is actually the last time UsageStats database is
+         * persisted before the actual shutdown. Events (if there are any) between this timestamp
+         * and the actual shutdown is not persisted in the database. So any open events without
+         * matching close events between DEVICE_SHUTDOWN and {@link #DEVICE_STARTUP} should be
+         * ignored because the closing time is unknown.</p>
          */
         public static final int DEVICE_SHUTDOWN = 26;
 
         /**
+         * An event type denoting that the Android runtime started up. This could be after a
+         * shutdown or a runtime restart. Any open events without matching close events between
+         * {@link #DEVICE_SHUTDOWN} and DEVICE_STARTUP should be ignored because the closing time is
+         * unknown.
+         */
+        public static final int DEVICE_STARTUP = 27;
+
+        /**
          * Keep in sync with the greatest event type value.
          * @hide
          */
-        public static final int MAX_EVENT_TYPE = 26;
+        public static final int MAX_EVENT_TYPE = 27;
 
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d758c4d..7b4dd19 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1448,14 +1448,33 @@
 
         /**
          * Request that rollbacks be enabled for the given upgrade.
+         *
+         * @removed
+         * @deprecated use {@link #setEnableRollback(boolean)} instead.
          * @hide
          */
+        @Deprecated
         @SystemApi
         public void setEnableRollback() {
             installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
         }
 
         /**
+         * Request that rollbacks be enabled or disabled for the given upgrade.
+         *
+         * @param enable set to {@code true} to enable, {@code false} to disable
+         * @hide
+         */
+        @SystemApi
+        public void setEnableRollback(boolean enable) {
+            if (enable) {
+                installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
+            } else {
+                installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+            }
+        }
+
+        /**
          * @deprecated use {@link #setRequestDowngrade(boolean)}.
          * {@hide}
          */
@@ -2058,6 +2077,16 @@
         }
 
         /**
+         * Return whether rollback is enabled or disabled for the given upgrade.
+         *
+         * @hide
+         */
+        @SystemApi
+        public boolean getEnableRollback() {
+            return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
+        }
+
+        /**
          * Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
          *
          * @hide
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c4a574a..89c0690 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1843,7 +1843,8 @@
             }
         }
 
-        final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q;
+        // TODO: flip the default based on targetSdkVersion when possible.  See b/128335904.
+        final boolean extractNativeLibsDefault = true;
         final boolean extractNativeLibs = (extractNativeLibsProvided != null)
                 ? extractNativeLibsProvided : extractNativeLibsDefault;
 
@@ -3718,11 +3719,10 @@
             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
         }
 
-        final boolean extractNativeLibsDefault =
-                owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;
+        // TODO: flip the default based on targetSdkVersion when possible.  See b/128335904.
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
-                extractNativeLibsDefault)) {
+                true)) {
             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
         }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c855d45..6729242 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1396,9 +1396,11 @@
 
 
     /**
+     * Returns the resource ID of the resource that was used to create this AttributeSet.
+     *
      * @param set AttributeSet for which we want to find the source.
-     * @return The resource id for the source that is backing the given AttributeSet
-     * @hide
+     * @return The resource ID for the source that is backing the given AttributeSet or
+     * {@link Resources#ID_NULL} if the AttributeSet is {@code null}.
      */
     @AnyRes
     public static int getAttributeSetSourceResId(@Nullable AttributeSet set) {
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 03810f5..c0414fc 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -89,6 +89,7 @@
     /**
      * Returns the name of the package to roll back from.
      */
+    @NonNull
     public String getPackageName() {
         return mVersionRolledBackFrom.getPackageName();
     }
@@ -96,6 +97,7 @@
     /**
      * Returns the version of the package rolled back from.
      */
+    @NonNull
     public VersionedPackage getVersionRolledBackFrom() {
         return mVersionRolledBackFrom;
     }
@@ -103,6 +105,7 @@
     /**
      * Returns the version of the package rolled back to.
      */
+    @NonNull
     public VersionedPackage getVersionRolledBackTo() {
         return mVersionRolledBackTo;
     }
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 29b99e0..a363718 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.rollback;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.pm.VersionedPackage;
 import android.os.Parcel;
@@ -72,6 +73,7 @@
     /**
      * Returns the list of package that are rolled back.
      */
+    @NonNull
     public List<PackageRollbackInfo> getPackages() {
         return mPackages;
     }
@@ -105,6 +107,7 @@
      * As provided to {@link #commitRollback} when the rollback was committed.
      * This is only applicable for rollbacks that have been committed.
      */
+    @NonNull
     public List<VersionedPackage> getCausePackages() {
         return mCausePackages;
     }
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c043491..4e8c254 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -57,6 +57,7 @@
      *            MANAGE_ROLLBACKS permission.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @NonNull
     public List<RollbackInfo> getAvailableRollbacks() {
         try {
             return mBinder.getAvailableRollbacks().getList();
diff --git a/core/java/android/net/IpMemoryStore.java b/core/java/android/net/IpMemoryStore.java
index b35f097..2f4d9bc 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/core/java/android/net/IpMemoryStore.java
@@ -171,4 +171,9 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /** Gets an instance of the memory store */
+    public static IpMemoryStore getMemoryStore(final Context context) {
+        return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
+    }
 }
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index af7d11d..bda4e27 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -476,10 +476,6 @@
          */
         @NonNull
         public BatterySaverPolicyConfig build() {
-            if (!mEnableAdjustBrightness && Float.compare(1f, mAdjustBrightnessFactor) != 0) {
-                throw new IllegalArgumentException("Brightness adjustment factor changed without "
-                        + "enabling brightness adjustment");
-            }
             return new BatterySaverPolicyConfig(this);
         }
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b7e65b9..e4277e4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4761,6 +4761,9 @@
         sb.append(")");
         pw.println(sb.toString());
 
+        printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
+                getModemControllerActivity(), which);
+
         pw.print("     Cellular data received: "); pw.println(formatBytesLocked(mobileRxTotalBytes));
         pw.print("     Cellular data sent: "); pw.println(formatBytesLocked(mobileTxTotalBytes));
         pw.print("     Cellular packets received: "); pw.println(mobileRxTotalPackets);
@@ -4818,9 +4821,6 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
-            getModemControllerActivity(), which);
-
         pw.print(prefix);
         sb.setLength(0);
         sb.append(prefix);
@@ -4837,6 +4837,9 @@
         sb.append(")");
         pw.println(sb.toString());
 
+        printControllerActivity(pw, sb, prefix, WIFI_CONTROLLER_NAME,
+                getWifiControllerActivity(), which);
+
         pw.print("     Wifi data received: "); pw.println(formatBytesLocked(wifiRxTotalBytes));
         pw.print("     Wifi data sent: "); pw.println(formatBytesLocked(wifiTxTotalBytes));
         pw.print("     Wifi packets received: "); pw.println(wifiRxTotalPackets);
@@ -4914,9 +4917,6 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        printControllerActivity(pw, sb, prefix, WIFI_CONTROLLER_NAME,
-            getWifiControllerActivity(), which);
-
         pw.print(prefix);
         sb.setLength(0);
         sb.append(prefix);
@@ -4949,8 +4949,10 @@
             pw.print(prefix);
             sb.setLength(0);
             sb.append(prefix);
-            sb.append("     Battery Drain (mAh): ");
-            sb.append(Double.toString(((double) gpsBatteryDrainMaMs)/(3600 * 1000)));
+            sb.append("     GPS Battery Drain: ");
+            sb.append(new DecimalFormat("#.##").format(
+                    ((double) gpsBatteryDrainMaMs) / (3600 * 1000)));
+            sb.append("mAh");
             pw.println(sb.toString());
         }
 
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 684369a..672624c 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -39,7 +40,7 @@
  */
 @SystemApi
 @SystemService(Context.BUGREPORT_SERVICE)
-public class BugreportManager {
+public final class BugreportManager {
     private final Context mContext;
     private final IDumpstate mBinder;
 
@@ -90,7 +91,7 @@
          * Called when there is a progress update.
          * @param progress the progress in [0.0, 100.0]
          */
-        public void onProgress(float progress) {}
+        public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
 
         /**
          * Called when taking bugreport resulted in an error.
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index 3871375..279ccae 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -41,6 +41,7 @@
 
     /**
      * Defines acceptable types of bugreports.
+     * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "BUGREPORT_MODE_" }, value = {
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 1df3dad..5cf3b97 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -39,8 +39,9 @@
  *
  * The APIs defined in this class and UpdateEngineCallback class must be in
  * sync with the ones in
- * system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl and
- * system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl.
+ * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl}
+ * and
+ * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}.
  *
  * {@hide}
  */
@@ -51,39 +52,150 @@
     private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
 
     /**
-     * Error code from the update engine. Values must agree with the ones in
-     * system/update_engine/common/error_code.h.
+     * Error codes from update engine upon finishing a call to
+     * {@link applyPayload}. Values will be passed via the callback function
+     * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must
+     * agree with the ones in {@code system/update_engine/common/error_code.h}.
      */
     public static final class ErrorCodeConstants {
+        /**
+         * Error code: a request finished successfully.
+         */
         public static final int SUCCESS = 0;
+        /**
+         * Error code: a request failed due to a generic error.
+         */
         public static final int ERROR = 1;
+        /**
+         * Error code: an update failed to apply due to filesystem copier
+         * error.
+         */
         public static final int FILESYSTEM_COPIER_ERROR = 4;
+        /**
+         * Error code: an update failed to apply due to an error in running
+         * post-install hooks.
+         */
         public static final int POST_INSTALL_RUNNER_ERROR = 5;
+        /**
+         * Error code: an update failed to apply due to a mismatching payload.
+         *
+         * <p>For example, the given payload uses a feature that's not
+         * supported by the current update engine.
+         */
         public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
+        /**
+         * Error code: an update failed to apply due to an error in opening
+         * devices.
+         */
         public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
+        /**
+         * Error code: an update failed to apply due to an error in opening
+         * kernel device.
+         */
         public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
+        /**
+         * Error code: an update failed to apply due to an error in fetching
+         * the payload.
+         *
+         * <p>For example, this could be a result of bad network connection
+         * when streaming an update.
+         */
         public static final int DOWNLOAD_TRANSFER_ERROR = 9;
+        /**
+         * Error code: an update failed to apply due to a mismatch in payload
+         * hash.
+         *
+         * <p>Update engine does sanity checks for the given payload and its
+         * metadata.
+         */
         public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
+
+        /**
+         * Error code: an update failed to apply due to a mismatch in payload
+         * size.
+         */
         public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
+
+        /**
+         * Error code: an update failed to apply due to failing to verify
+         * payload signatures.
+         */
         public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+
+        /**
+         * Error code: an update failed to apply due to a downgrade in payload
+         * timestamp.
+         *
+         * <p>The timestamp of a build is encoded into the payload, which will
+         * be enforced during install to prevent downgrading a device.
+         */
         public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
+
+        /**
+         * Error code: an update has been applied successfully but the new slot
+         * hasn't been set to active.
+         *
+         * <p>It indicates a successful finish of calling {@link #applyPayload} with
+         * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
+         */
         public static final int UPDATED_BUT_NOT_ACTIVE = 52;
     }
 
     /**
-     * Update status code from the update engine. Values must agree with the
-     * ones in system/update_engine/client_library/include/update_engine/update_status.h.
+     * Status codes for update engine. Values must agree with the ones in
+     * {@code system/update_engine/client_library/include/update_engine/update_status.h}.
      */
     public static final class UpdateStatusConstants {
+        /**
+         * Update status code: update engine is in idle state.
+         */
         public static final int IDLE = 0;
+
+        /**
+         * Update status code: update engine is checking for update.
+         */
         public static final int CHECKING_FOR_UPDATE = 1;
+
+        /**
+         * Update status code: an update is available.
+         */
         public static final int UPDATE_AVAILABLE = 2;
+
+        /**
+         * Update status code: update engine is downloading an update.
+         */
         public static final int DOWNLOADING = 3;
+
+        /**
+         * Update status code: update engine is verifying an update.
+         */
         public static final int VERIFYING = 4;
+
+        /**
+         * Update status code: update engine is finalizing an update.
+         */
         public static final int FINALIZING = 5;
+
+        /**
+         * Update status code: an update has been applied and is pending for
+         * reboot.
+         */
         public static final int UPDATED_NEED_REBOOT = 6;
+
+        /**
+         * Update status code: update engine is reporting an error event.
+         */
         public static final int REPORTING_ERROR_EVENT = 7;
+
+        /**
+         * Update status code: update engine is attempting to rollback an
+         * update.
+         */
         public static final int ATTEMPTING_ROLLBACK = 8;
+
+        /**
+         * Update status code: update engine is in disabled state.
+         */
         public static final int DISABLED = 9;
     }
 
@@ -178,6 +290,18 @@
      *   "METADATA_SIZE=70604"
      * };
      * </pre>
+     *
+     * <p>The callback functions registered via {@code #bind} will be called
+     * during and at the end of the payload application.
+     *
+     * <p>By default the newly updated slot will be set active upon
+     * successfully finishing an update. Device will attempt to boot into the
+     * new slot on next reboot. This behavior can be customized by specifying
+     * {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which
+     * allows the caller to later determine a good time to boot into the new
+     * slot. Calling {@code applyPayload} again with the same payload but with
+     * {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new
+     * slot active, after verifying its integrity.
      */
     public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
         try {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 4263377..185df5e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
@@ -954,6 +955,21 @@
     public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
 
     /**
+     * Specifies if the current user is able to receive content suggestions for selections based on
+     * the contents of their screen.
+     *
+     * <p>Device owner and profile owner can set this restriction. When it is set by device owner,
+     * only the target user will be affected.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONTENT_SUGGESTIONS = "no_content_suggestions";
+
+    /**
      * Specifies if user switching is blocked on the current user.
      *
      * <p> This restriction can only be set by the device owner, it will be applied to all users.
@@ -1102,6 +1118,47 @@
     public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
 
     /**
+     * Indicates that users are switchable.
+     * @hide
+     */
+    @SystemApi
+    public static final int SWITCHABILITY_STATUS_OK = 0;
+
+    /**
+     * Indicated that the user is in a phone call.
+     * @hide
+     */
+    @SystemApi
+    public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1 << 0;
+
+    /**
+     * Indicates that user switching is disallowed ({@link #DISALLOW_USER_SWITCH} is set).
+     * @hide
+     */
+    @SystemApi
+    public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 1 << 1;
+
+    /**
+     * Indicates that the system user is locked and user switching is not allowed.
+     * @hide
+     */
+    @SystemApi
+    public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 1 << 2;
+
+    /**
+     * Result returned in {@link #getUserSwitchability()} indicating user swichability.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "SWITCHABILITY_STATUS_" }, value = {
+            SWITCHABILITY_STATUS_OK,
+            SWITCHABILITY_STATUS_USER_IN_CALL,
+            SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED,
+            SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED
+    })
+    public @interface UserSwitchabilityResult {}
+
+    /**
      * Indicates user operation is successful.
      */
     public static final int USER_OPERATION_SUCCESS = 0;
@@ -1223,14 +1280,13 @@
     }
 
     /**
-     * Returns whether switching users is currently allowed.
-     * <p>For instance switching users is not allowed if the current user is in a phone call,
-     * system user hasn't been unlocked yet, or {@link #DISALLOW_USER_SWITCH} is set.
+     * @deprecated use {@link #getUserSwitchability()} instead.
+     *
+     * @removed
      * @hide
      */
-    @SystemApi
-    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
-            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    @Deprecated
+    @UnsupportedAppUsage
     public boolean canSwitchUsers() {
         boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
                 mContext.getContentResolver(),
@@ -1244,6 +1300,42 @@
     }
 
     /**
+     * Returns whether switching users is currently allowed.
+     * <p>
+     * Switching users is not allowed in the following cases:
+     * <li>the user is in a phone call</li>
+     * <li>{@link #DISALLOW_USER_SWITCH} is set</li>
+     * <li>system user hasn't been unlocked yet</li>
+     *
+     * @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE,
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    public @UserSwitchabilityResult int getUserSwitchability() {
+        final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
+        final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+        final TelephonyManager tm =
+                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+        int flags = SWITCHABILITY_STATUS_OK;
+        if (tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+            flags |= SWITCHABILITY_STATUS_USER_IN_CALL;
+        }
+        if (hasUserRestriction(DISALLOW_USER_SWITCH)) {
+            flags |= SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED;
+        }
+        if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
+            flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
+        }
+        return flags;
+    }
+
+    /**
      * Returns the user handle for the user that this process is running under.
      *
      * @return the user handle of this process.
@@ -2655,11 +2747,16 @@
      * Removes a user and all associated data.
      *
      * @param user the user that needs to be removed.
+     * @return {@code true} if the user was successfully removed, {@code false} otherwise.
+     * @throws IllegalArgumentException if {@code user} is {@code null}
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public boolean removeUser(UserHandle user) {
+    public boolean removeUser(@NonNull UserHandle user) {
+        if (user == null) {
+            throw new IllegalArgumentException("user cannot be null");
+        }
         return removeUser(user.getIdentifier());
     }
 
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 0ac7c37..e4593e5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -30,6 +30,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.provider.Settings.ResetMode;
+import android.util.ArrayMap;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
@@ -398,8 +399,11 @@
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
-    private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
-            new HashMap<>();
+    private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
+            new ArrayMap<>();
+    @GuardedBy("sLock")
+    private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
+            new ArrayMap<>();
     @GuardedBy("sLock")
     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
 
@@ -597,20 +601,58 @@
             @NonNull String namespace,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnPropertyChangedListener onPropertyChangedListener) {
-        // TODO enforce READ_DEVICE_CONFIG permission
         synchronized (sLock) {
-            Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
+            Pair<String, Executor> oldNamespace = sSingleListeners.get(onPropertyChangedListener);
             if (oldNamespace == null) {
                 // Brand new listener, add it to the list.
-                sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+                sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
                 incrementNamespace(namespace);
             } else if (namespace.equals(oldNamespace.first)) {
                 // Listener is already registered for this namespace, update executor just in case.
-                sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+                sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
             } else {
                 // Update this listener from an old namespace to the new one.
-                decrementNamespace(sListeners.get(onPropertyChangedListener).first);
-                sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+                decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
+                sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+                incrementNamespace(namespace);
+            }
+        }
+    }
+
+    /**
+     * Add a listener for property changes.
+     * <p>
+     * This listener will be called whenever properties in the specified namespace change. Callbacks
+     * will be made on the specified executor. Future calls to this method with the same listener
+     * will replace the old namespace and executor. Remove the listener entirely by calling
+     * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
+     *
+     * @param namespace                   The namespace containing properties to monitor.
+     * @param executor                    The executor which will be used to run callbacks.
+     * @param onPropertiesChangedListener The listener to add.
+     * @hide
+     * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
+    public static void addOnPropertiesChangedListener(
+            @NonNull String namespace,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
+        synchronized (sLock) {
+            Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
+            if (oldNamespace == null) {
+                // Brand new listener, add it to the list.
+                sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
+                incrementNamespace(namespace);
+            } else if (namespace.equals(oldNamespace.first)) {
+                // Listener is already registered for this namespace, update executor just in case.
+                sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
+            } else {
+                // Update this listener from an old namespace to the new one.
+                decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
+                sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
                 incrementNamespace(namespace);
             }
         }
@@ -627,11 +669,33 @@
     @SystemApi
     @TestApi
     public static void removeOnPropertyChangedListener(
-            OnPropertyChangedListener onPropertyChangedListener) {
+            @NonNull OnPropertyChangedListener onPropertyChangedListener) {
+        Preconditions.checkNotNull(onPropertyChangedListener);
         synchronized (sLock) {
-            if (sListeners.containsKey(onPropertyChangedListener)) {
-                decrementNamespace(sListeners.get(onPropertyChangedListener).first);
-                sListeners.remove(onPropertyChangedListener);
+            if (sSingleListeners.containsKey(onPropertyChangedListener)) {
+                decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
+                sSingleListeners.remove(onPropertyChangedListener);
+            }
+        }
+    }
+
+    /**
+     * Remove a listener for property changes. The listener will receive no further notification of
+     * property changes.
+     *
+     * @param onPropertiesChangedListener The listener to remove.
+     * @hide
+     * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
+     */
+    @SystemApi
+    @TestApi
+    public static void removeOnPropertiesChangedListener(
+            @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
+        Preconditions.checkNotNull(onPropertiesChangedListener);
+        synchronized (sLock) {
+            if (sListeners.containsKey(onPropertiesChangedListener)) {
+                decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
+                sListeners.remove(onPropertiesChangedListener);
             }
         }
     }
@@ -700,14 +764,30 @@
         final String name = pathSegments.get(2);
         final String value = getProperty(namespace, name);
         synchronized (sLock) {
-            for (final OnPropertyChangedListener listener : sListeners.keySet()) {
-                if (namespace.equals(sListeners.get(listener).first)) {
-                    sListeners.get(listener).second.execute(new Runnable() {
+            // OnPropertiesChangedListeners
+            for (int i = 0; i < sListeners.size(); i++) {
+                if (namespace.equals(sListeners.valueAt(i).first)) {
+                    final int j = i;
+                    sListeners.valueAt(i).second.execute(new Runnable() {
                         @Override
                         public void run() {
                             Map<String, String> propertyMap = new HashMap(1);
                             propertyMap.put(name, value);
-                            listener.onPropertiesChanged(new Properties(namespace, propertyMap));
+                            sListeners.keyAt(j)
+                                    .onPropertiesChanged(new Properties(namespace, propertyMap));
+                        }
+
+                    });
+                }
+            }
+            // OnPropertyChangedListeners
+            for (int i = 0; i < sSingleListeners.size(); i++) {
+                if (namespace.equals(sSingleListeners.valueAt(i).first)) {
+                    final int j = i;
+                    sSingleListeners.valueAt(i).second.execute(new Runnable() {
+                        @Override
+                        public void run() {
+                            sSingleListeners.keyAt(j).onPropertyChanged(namespace, name, value);
                         }
 
                     });
@@ -717,7 +797,7 @@
     }
 
     /**
-     * Interface for monitoring to properties.
+     * Interface for monitoring single property changes.
      * <p>
      * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes.
      *
@@ -734,22 +814,25 @@
          * @param value     The new value of the property which has changed.
          */
         void onPropertyChanged(String namespace, String name, String value);
+    }
 
+    /**
+     * Interface for monitoring changes to properties.
+     * <p>
+     * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public interface OnPropertiesChangedListener {
         /**
          * Called when one or more properties have changed.
          *
          * @param properties Contains the complete collection of properties which have changed for a
-         *         single namespace.
+         *                   single namespace.
          */
-        default void onPropertiesChanged(@NonNull Properties properties) {
-            // During the transitional period, this method calls the old one to ensure legacy
-            // callers continue to function as expected. Ignore this if you are implementing it for
-            // yourself.
-            String namespace = properties.getNamespace();
-            for (String name : properties.getKeyset()) {
-                onPropertyChanged(namespace, name, properties.getString(name, null));
-            }
-        }
+        void onPropertiesChanged(@NonNull Properties properties);
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5f36373..4836e6c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1686,14 +1686,7 @@
      * Input: Nothing.
      *
      * <p>
-     * Output: {@link android.app.Activity#RESULT_OK} if user enabled Content Capture,
-     * {@link android.app.Activity#RESULT_CANCELED} if user disabled it, cancelled, or if the caller
-     * is not the Content Capture service associated with the user.
-     *
-     * <p>
-     * <b>NOTE: </b> Caller should call
-     * {@link android.view.contentcapture.ContentCaptureManager#isContentCaptureFeatureEnabled()}
-     * first to check whether the feature is already enabled.
+     * Output: Nothing
      *
      * @hide
      */
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 87bdfe0..780b576 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -373,7 +373,10 @@
                     args.recycle();
                     Adjustment adjustment = onNotificationEnqueued(sbn, channel);
                     if (adjustment != null) {
-                        if (!isBound()) return;
+                        if (!isBound()) {
+                            Log.w(TAG, "MSG_ON_NOTIFICATION_ENQUEUED: service not bound, skip.");
+                            return;
+                        }
                         try {
                             getNotificationInterface().applyEnqueuedAdjustmentFromAssistant(
                                     mWrapper, adjustment);
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 4315100..cc74e1a 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -63,9 +63,6 @@
 
     private Context mContext; // used for inflation & icon expansion
 
-    // Contains the basic logging data of the notification.
-    private LogMaker mLogMaker;
-
     /** @hide */
     public StatusBarNotification(String pkg, String opPkg, int id,
             String tag, int uid, int initialPid, Notification notification, UserHandle user,
@@ -404,24 +401,15 @@
      * @hide
      */
     public LogMaker getLogMaker() {
-        if (mLogMaker == null) {
-            // Initialize fields that only change on update (so a new record).
-            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
-                .setPackageName(getPackageName())
+        return new LogMaker(MetricsEvent.VIEW_UNKNOWN).setPackageName(getPackageName())
                 .addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
                 .addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
-                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
-        }
-        // Reset fields that can change between updates, or are used by multiple logs.
-        return mLogMaker
-            .clearCategory()
-            .clearType()
-            .clearSubtype()
-            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
-            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
-                getNotification().isGroupSummary() ? 1 : 0)
-            .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
-                    getNotification().category);
+                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag())
+                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
+                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
+                        getNotification().isGroupSummary() ? 1 : 0)
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
+                        getNotification().category);
     }
 
     private String getGroupLogTag() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 1382fbc..2d7e179 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -142,6 +142,10 @@
                 && legacyContentInsets != null && legacyStableInsets != null) {
             WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets);
             WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets);
+
+            // TODO: set system gesture insets based on actual system gesture area.
+            typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
+            typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
         }
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources.get(type);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6ff699e..cb64ab1 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
@@ -193,7 +194,7 @@
      *
      * @param from The SurfaceControl to assosciate this Surface with
      */
-    public Surface(SurfaceControl from) {
+    public Surface(@NonNull SurfaceControl from) {
         copyFrom(from);
     }
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5e2aaae..998ad2a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -459,6 +459,7 @@
          * Construct a new {@link SurfaceControl} with the set parameters. The builder
          * remains valid.
          */
+        @NonNull
         public SurfaceControl build() {
             if (mWidth < 0 || mHeight < 0) {
                 throw new IllegalArgumentException(
@@ -477,7 +478,8 @@
          *
          * @param name A name to identify the Surface in debugging.
          */
-        public Builder setName(String name) {
+        @NonNull
+        public Builder setName(@NonNull String name) {
             mName = name;
             return this;
         }
@@ -488,6 +490,7 @@
          * @param width The buffer width in pixels.
          * @param height The buffer height in pixels.
          */
+        @NonNull
         public Builder setBufferSize(@IntRange(from = 0) int width,
                 @IntRange(from = 0) int height) {
             if (width < 0 || height < 0) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2479497..7fcce6d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24116,7 +24116,7 @@
      *
      * @param matrix input matrix to modify
      */
-    public void transformMatrixToGlobal(Matrix matrix) {
+    public void transformMatrixToGlobal(@NonNull Matrix matrix) {
         final ViewParent parent = mParent;
         if (parent instanceof View) {
             final View vp = (View) parent;
@@ -24141,7 +24141,7 @@
      *
      * @param matrix input matrix to modify
      */
-    public void transformMatrixToLocal(Matrix matrix) {
+    public void transformMatrixToLocal(@NonNull Matrix matrix) {
         final ViewParent parent = mParent;
         if (parent instanceof View) {
             final View vp = (View) parent;
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f3bbca3..f1a992c 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -27,6 +27,7 @@
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.compatSystemInsets;
 import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemGestures;
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -220,6 +221,8 @@
         }
         Insets[] typeInsetMap = new Insets[SIZE];
         assignCompatInsets(typeInsetMap, insets);
+        // TODO: set system gesture insets based on actual system gesture area.
+        typeInsetMap[indexOf(systemGestures())] = Insets.of(insets);
         return typeInsetMap;
     }
 
@@ -229,7 +232,6 @@
     static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
         typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
         typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
-        typeInsetMap[indexOf(SYSTEM_GESTURES)] = Insets.of(insets);
     }
 
     private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
@@ -675,6 +677,7 @@
     public String toString() {
         return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
                 + " stableInsets=" + getStableInsets()
+                + " sysGestureInsets=" + getSystemGestureInsets()
                 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
                 + (isRound() ? " round" : "")
                 + "}";
diff --git a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
similarity index 76%
rename from core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
rename to core/java/android/view/inspector/StaticInspectionCompanionProvider.java
index d4b7e85..42a892d 100644
--- a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
+++ b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
@@ -20,15 +20,15 @@
 import android.annotation.Nullable;
 
 /**
- * An inspection companion provider that loads pre-generated inspection companions
+ * An inspection companion provider that finds companions as inner classes or generated code.
  *
  * @see android.processor.view.inspector.PlatformInspectableProcessor
  */
-public class GeneratedInspectionCompanionProvider implements InspectionCompanionProvider {
+public class StaticInspectionCompanionProvider implements InspectionCompanionProvider {
     /**
-     * The suffix used for the generated class
+     * The suffix used for the generated classes and inner classes
      */
-    private static final String COMPANION_SUFFIX = "$$InspectionCompanion";
+    private static final String COMPANION_SUFFIX = "$InspectionCompanion";
 
     @Override
     @Nullable
@@ -39,7 +39,12 @@
         try {
             final Class<InspectionCompanion<T>> companionClass =
                     (Class<InspectionCompanion<T>>) cls.getClassLoader().loadClass(companionName);
-            return companionClass.newInstance();
+
+            if (InspectionCompanion.class.isAssignableFrom(companionClass)) {
+                return companionClass.newInstance();
+            } else {
+                return null;
+            }
         } catch (ClassNotFoundException e) {
             return null;
         } catch (IllegalAccessException e) {
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 78ed9bf..dc75212 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -318,19 +318,15 @@
         private final List<String> mHints;
         @Nullable
         private String mCallingPackageName;
-        @Nullable
-        private final String mConversationId;
 
         private Request(
                 @NonNull List<Message> conversation,
                 @NonNull TextClassifier.EntityConfig typeConfig,
                 int maxSuggestions,
-                String conversationId,
                 @Nullable @Hint List<String> hints) {
             mConversation = Preconditions.checkNotNull(conversation);
             mTypeConfig = Preconditions.checkNotNull(typeConfig);
             mMaxSuggestions = maxSuggestions;
-            mConversationId = conversationId;
             mHints = hints;
         }
 
@@ -339,7 +335,6 @@
             in.readParcelableList(conversation, null);
             TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
             int maxSuggestions = in.readInt();
-            String conversationId = in.readString();
             List<String> hints = new ArrayList<>();
             in.readStringList(hints);
             String callingPackageName = in.readString();
@@ -348,7 +343,6 @@
                     conversation,
                     typeConfig,
                     maxSuggestions,
-                    conversationId,
                     hints);
             request.setCallingPackageName(callingPackageName);
             return request;
@@ -359,7 +353,6 @@
             parcel.writeParcelableList(mConversation, flags);
             parcel.writeParcelable(mTypeConfig, flags);
             parcel.writeInt(mMaxSuggestions);
-            parcel.writeString(mConversationId);
             parcel.writeStringList(mHints);
             parcel.writeString(mCallingPackageName);
         }
@@ -403,16 +396,6 @@
             return mMaxSuggestions;
         }
 
-        /**
-         * Return an unique identifier of the conversation that is generating actions for. This
-         * identifier is unique within the calling package only, so use it with
-         * {@link #getCallingPackageName()}.
-         */
-        @Nullable
-        public String getConversationId() {
-            return mConversationId;
-        }
-
         /** Returns an immutable list of hints */
         @Nullable
         @Hint
@@ -448,8 +431,6 @@
             private TextClassifier.EntityConfig mTypeConfig;
             private int mMaxSuggestions = -1;
             @Nullable
-            private String mConversationId;
-            @Nullable
             @Hint
             private List<String> mHints;
 
@@ -490,15 +471,6 @@
                 return this;
             }
 
-            /**
-             * Sets an unique identifier of the conversation that is generating actions for.
-             */
-            @NonNull
-            public Builder setConversationId(@Nullable String conversationId) {
-                mConversationId = conversationId;
-                return this;
-            }
-
             /** Builds the {@link Request} object. */
             @NonNull
             public Request build() {
@@ -508,7 +480,6 @@
                                 ? new TextClassifier.EntityConfig.Builder().build()
                                 : mTypeConfig,
                         mMaxSuggestions,
-                        mConversationId,
                         mHints == null
                                 ? Collections.emptyList()
                                 : Collections.unmodifiableList(mHints));
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3555822..034cabd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1704,7 +1704,7 @@
 
 
     /**
-     * Gets the WebView renderer associated with this WebView.
+     * Gets a handle to the WebView renderer process associated with this WebView.
      *
      * <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
      * run in "multiprocess" mode. In multiprocess mode, rendering of web
@@ -1717,67 +1717,70 @@
      * handle to the renderer process associated with the WebView, which can
      * be used to control the renderer process.
      *
-     * @return the {@link WebViewRenderer} renderer handle associated
+     * @return the {@link WebViewRenderProcess} renderer handle associated
      *         with this {@link WebView}, or {@code null} if
      *         WebView is not runing in multiprocess mode.
      */
     @Nullable
-    public WebViewRenderer getWebViewRenderer() {
+    public WebViewRenderProcess getWebViewRenderProcess() {
         checkThread();
-        return mProvider.getWebViewRenderer();
+        return mProvider.getWebViewRenderProcess();
     }
 
     /**
      * Sets the renderer client object associated with this WebView.
      *
      * <p>The renderer client encapsulates callbacks relevant to WebView renderer
-     * state. See {@link WebViewRendererClient} for details.
+     * state. See {@link WebViewRenderProcessClient} for details.
      *
      * <p>Although many WebView instances may share a single underlying
      * renderer, and renderers may live either in the application
      * process, or in a sandboxed process that is isolated from the
-     * application process, instances of {@link WebViewRendererClient}
+     * application process, instances of {@link WebViewRenderProcessClient}
      * are set per-WebView.  Callbacks represent renderer events from
      * the perspective of this WebView, and may or may not be correlated
      * with renderer events affecting other WebViews.
      *
-     * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
-     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     * @param executor the Executor on which {@link WebViewRenderProcessClient}
+     *                 callbacks will execute.
+     * @param webViewRenderProcessClient the {@link WebViewRenderProcessClient}
+     *                                   object.
      */
-    public void setWebViewRendererClient(
+    public void setWebViewRenderProcessClient(
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull WebViewRendererClient webViewRendererClient) {
+            @NonNull WebViewRenderProcessClient webViewRenderProcessClient) {
         checkThread();
-        mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+        mProvider.setWebViewRenderProcessClient(
+                executor, webViewRenderProcessClient);
     }
 
     /**
      * Sets the renderer client object associated with this WebView.
      *
-     * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+     * See {@link #setWebViewRenderProcessClient(Executor,WebViewRenderProcessClient)} for details.
      *
-     * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+     * <p> {@link WebViewRenderProcessClient} callbacks will run on the thread that this WebView was
      * initialized on.
      *
-     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     * @param webViewRenderProcessClient the {@link WebViewRenderProcessClient} object.
      */
-    public void setWebViewRendererClient(
-            @Nullable WebViewRendererClient webViewRendererClient) {
+    public void setWebViewRenderProcessClient(
+            @Nullable WebViewRenderProcessClient webViewRenderProcessClient) {
         checkThread();
-        mProvider.setWebViewRendererClient(null, webViewRendererClient);
+        mProvider.setWebViewRenderProcessClient(null, webViewRenderProcessClient);
     }
 
     /**
      * Gets the renderer client object associated with this WebView.
      *
-     * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
-     * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
-     * otherwise.
+     * @return the {@link WebViewRenderProcessClient} object associated with this WebView, if one
+     *         has been set via {@link #setWebViewRenderProcessClient(WebViewRenderProcessClient)}
+     *         or {@code null} otherwise.
      */
     @Nullable
-    public WebViewRendererClient getWebViewRendererClient() {
+    public WebViewRenderProcessClient getWebViewRenderProcessClient() {
         checkThread();
-        return mProvider.getWebViewRendererClient();
+        return mProvider.getWebViewRenderProcessClient();
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 090640e..150fa88 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -102,9 +102,11 @@
 
     /**
      * Notify the host application that a page has finished loading. This method
-     * is called only for main frame. When onPageFinished() is called, the
-     * rendering picture may not be updated yet. To get the notification for the
-     * new Picture, use {@link WebView.PictureListener#onNewPicture}.
+     * is called only for main frame. Receiving an {@code onPageFinished()} callback does not
+     * guarantee that the next frame drawn by WebView will reflect the state of the DOM at this
+     * point. In order to be notified that the current DOM state is ready to be rendered, request a
+     * visual state callback with {@link WebView#postVisualStateCallback} and wait for the supplied
+     * callback to be triggered.
      *
      * @param view The WebView that is initiating the callback.
      * @param url The url of the page.
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 4c8f72a..010c0b7 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -238,13 +238,15 @@
 
     public WebViewClient getWebViewClient();
 
-    public WebViewRenderer getWebViewRenderer();
+    @Nullable
+    public WebViewRenderProcess getWebViewRenderProcess();
 
-    public void setWebViewRendererClient(
+    public void setWebViewRenderProcessClient(
             @Nullable Executor executor,
-            @Nullable WebViewRendererClient client);
+            @Nullable WebViewRenderProcessClient client);
 
-    public WebViewRendererClient getWebViewRendererClient();
+    @Nullable
+    public WebViewRenderProcessClient getWebViewRenderProcessClient();
 
     public void setDownloadListener(DownloadListener listener);
 
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderProcess.java
similarity index 82%
rename from core/java/android/webkit/WebViewRenderer.java
rename to core/java/android/webkit/WebViewRenderProcess.java
index fc38cd9..1be2210 100644
--- a/core/java/android/webkit/WebViewRenderer.java
+++ b/core/java/android/webkit/WebViewRenderProcess.java
@@ -16,12 +16,10 @@
 
 package android.webkit;
 
-import android.annotation.SystemApi;
-
 /**
- * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ * WebViewRenderProcess provides an opaque handle to a {@link WebView} renderer.
  */
-public abstract class WebViewRenderer {
+public abstract class WebViewRenderProcess {
     /**
      * Cause this renderer to terminate.
      *
@@ -38,11 +36,6 @@
      */
     public abstract boolean terminate();
 
-    /**
-     * This class cannot be created by applications.
-     * @hide
-     */
-    @SystemApi
-    public WebViewRenderer() {
+    public WebViewRenderProcess() {
     }
 }
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRenderProcessClient.java
similarity index 66%
rename from core/java/android/webkit/WebViewRendererClient.java
rename to core/java/android/webkit/WebViewRenderProcessClient.java
index 2fadf54..24b8fb5 100644
--- a/core/java/android/webkit/WebViewRendererClient.java
+++ b/core/java/android/webkit/WebViewRenderProcessClient.java
@@ -22,14 +22,14 @@
 /**
  * Used to receive callbacks on {@link WebView} renderer events.
  *
- * WebViewRendererClient instances may be set or retrieved via {@link
- * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
- * WebView#getWebViewRendererClient()}.
+ * WebViewRenderProcessClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRenderProcessClient(WebViewRenderProcessClient)} and {@link
+ * WebView#getWebViewRenderProcessClient()}.
  *
  * Instances may be attached to multiple WebViews, and thus a single renderer event may cause
  * a callback to be called multiple times with different WebView parameters.
  */
-public abstract class WebViewRendererClient {
+public abstract class WebViewRenderProcessClient {
     /**
      * Called when the renderer currently associated with {@code view} becomes unresponsive as a
      * result of a long running blocking task such as the execution of JavaScript.
@@ -40,8 +40,11 @@
      *
      * <p>This callback will continue to be called at regular intervals as long as the renderer
      * remains unresponsive. If the renderer becomes responsive again, {@link
-     * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
-     * subsequently be called unless another period of unresponsiveness is detected.
+     * WebViewRenderProcessClient#onRenderProcessResponsive} will be called once, and this method
+     * will not subsequently be called unless another period of unresponsiveness is detected.
+     *
+     * <p>The minimum interval between successive calls to {@code onRenderProcessUnresponsive} is 5
+     * seconds.
      *
      * <p>No action is taken by WebView as a result of this method call. Applications may
      * choose to terminate the associated renderer via the object that is passed to this callback,
@@ -50,28 +53,28 @@
      * with the same renderer. Failure to do so will result in application termination.
      *
      * @param view The {@link WebView} for which unresponsiveness was detected.
-     * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+     * @param renderer The {@link WebViewRenderProcess} that has become unresponsive,
      * or {@code null} if WebView is running in single process mode.
      */
-    public abstract void onRendererUnresponsive(
-            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+    public abstract void onRenderProcessUnresponsive(
+            @NonNull WebView view, @Nullable WebViewRenderProcess renderer);
 
     /**
      * Called once when an unresponsive renderer currently associated with {@code view} becomes
      * responsive.
      *
      * <p>After a WebView renderer becomes unresponsive, which is notified to the application by
-     * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
-     * renderer task to complete, returning the renderer to a responsive state. In that case,
-     * this method is called once to indicate responsiveness.
+     * {@link WebViewRenderProcessClient#onRenderProcessUnresponsive}, it is possible for the
+     * blocking renderer task to complete, returning the renderer to a responsive state. In that
+     * case, this method is called once to indicate responsiveness.
      *
      * <p>No action is taken by WebView as a result of this method call.
      *
      * @param view The {@link WebView} for which responsiveness was detected.
      *
-     * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
-     * WebView is running in single process mode.
+     * @param renderer The {@link WebViewRenderProcess} that has become responsive, or {@code null}
+     *                 if WebView is running in single process mode.
      */
-    public abstract void onRendererResponsive(
-            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+    public abstract void onRenderProcessResponsive(
+            @NonNull WebView view, @Nullable WebViewRenderProcess renderer);
 }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index dad2669..685e8de 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1587,6 +1587,7 @@
      * others.
      * @return The height of the divider
      */
+    @Px
     public int getSelectionDividerHeight() {
         return mSelectionDividerHeight;
     }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 17ed2a0..c095376 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1687,8 +1687,21 @@
      *
      * @return a unique 64-bit token handle which is needed to refer to this token later.
      */
-    public long addEscrowToken(byte[] token, int userId) {
-        return getLockSettingsInternal().addEscrowToken(token, userId);
+    public long addEscrowToken(byte[] token, int userId,
+            @Nullable EscrowTokenStateChangeCallback callback) {
+        return getLockSettingsInternal().addEscrowToken(token, userId, callback);
+    }
+
+    /**
+     * Callback interface to notify when an added escrow token has been activated.
+     */
+    public interface EscrowTokenStateChangeCallback {
+        /**
+         * The method to be called when the token is activated.
+         * @param handle 64 bit handle corresponding to the escrow token
+         * @param userid user for whom the escrow token has been added
+         */
+        void onEscrowTokenActivated(long handle, int userid);
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 90397df..d459bfb 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -29,15 +29,18 @@
      * or change user password.
      *
      * After adding, if the user currently has lockscreen password, he will need to perform a
-     * confirm credential operation in order to activate the token for future use. If the user
+     * confirm credential operation in order to activate the token for future use.
+     * Once the token is activated, the callback that is passed here is called.   If the user
      * has no secure lockscreen, then the token is activated immediately.
      *
      * @return a unique 64-bit token handle which is needed to refer to this token later.
      */
-    public abstract long addEscrowToken(byte[] token, int userId);
+    public abstract long addEscrowToken(byte[] token, int userId,
+            LockPatternUtils.EscrowTokenStateChangeCallback callback);
 
     /**
      * Remove an escrow token.
+     *
      * @return true if the given handle refers to a valid token previously returned from
      * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
      */
@@ -51,6 +54,7 @@
 
     /**
      * Set the lock credential.
+     *
      * @return true if password is set.
      */
     public abstract boolean setLockCredentialWithToken(byte[] credential, int type,
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index de86d92..e7d240a 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -126,6 +126,9 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (mImagePushIn > 0) {
+            if (this.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                mImagePushIn *= -1;
+            }
             mRightIcon.layout(mRightIcon.getLeft() + mImagePushIn, mRightIcon.getTop(),
                     mRightIcon.getRight()  + mImagePushIn, mRightIcon.getBottom());
         }
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
index c23ca83..4aa8acc 100644
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ b/core/res/res/layout/notification_material_media_seekbar.xml
@@ -50,7 +50,7 @@
             android:layout_height="wrap_content"
             android:layout_alignParentLeft="true"
             android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:gravity="left"
+            android:gravity="start"
         />
 
         <TextView android:id="@+id/notification_media_total_time"
@@ -59,7 +59,7 @@
             android:layout_height="wrap_content"
             android:layout_alignParentRight="true"
             android:layout_marginEnd="@dimen/notification_content_margin_end"
-            android:gravity="right"
+            android:gravity="end"
         />
     </FrameLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index a2ad3b9..4e6b712 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -24,6 +24,7 @@
         <item name="colorError">@color/error_color_device_default_dark</item>
         <item name="colorControlNormal">?attr/textColorPrimary</item>
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+        <item name="forceDarkAllowed">false</item>
 
         <!-- QS panel background -->
         <item name="colorBackgroundFloating">@color/black</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b7f594e..bfb6d24 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1950,7 +1950,7 @@
     <!-- The name of the package that will hold the browser role by default. -->
     <string name="config_defaultBrowser" translatable="false">@string/default_browser</string>
     <!-- The name of the package that will hold the dialer role by default. -->
-    <string name="config_defaultDialer" translatable="false">com.android.phone</string>
+    <string name="config_defaultDialer" translatable="false">com.android.dialer</string>
     <!-- The name of the package that will hold the SMS role by default. -->
     <string name="config_defaultSms" translatable="false">@string/default_sms_application</string>
     <!-- Whether the default emergency settings should be shown. -->
@@ -3943,4 +3943,8 @@
     <!-- The default peak refresh rate for a given device. Change this value if you want to allow
          for higher refresh rates to be automatically used out of the box -->
     <integer name="config_defaultPeakRefreshRate">60</integer>
+
+    <!-- The type of the light sensor to be used by the display framework for things like
+         auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
+    <string name="config_displayLightSensorType" translatable="false" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6671ff8..05cf419 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -280,9 +280,9 @@
     <!-- WFC, summary for Disabled -->
     <string name="wifi_calling_off_summary">Off</string>
     <!-- WFC, summary for Wi-Fi Preferred -->
-    <string name="wfc_mode_wifi_preferred_summary">Wi-Fi preferred</string>
+    <string name="wfc_mode_wifi_preferred_summary">Call over Wi-Fi</string>
     <!-- WFC, summary for Mobile data Preferred -->
-    <string name="wfc_mode_cellular_preferred_summary">Mobile preferred</string>
+    <string name="wfc_mode_cellular_preferred_summary">Call over mobile network</string>
     <!-- WFC, summary for Wi-Fi Only -->
     <string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 96a3d96..c7e19c5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3693,5 +3693,9 @@
   <java-symbol type="string" name="mime_type_presentation" />
   <java-symbol type="string" name="mime_type_presentation_ext" />
 
+  <!-- For high refresh rate displays -->
   <java-symbol type="integer" name="config_defaultPeakRefreshRate" />
+
+  <!-- For Auto-Brightness -->
+  <java-symbol type="string" name="config_displayLightSensorType" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index d100f40..04fa524 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import static android.provider.DeviceConfig.OnPropertiesChangedListener;
 import static android.provider.DeviceConfig.OnPropertyChangedListener;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -224,29 +225,31 @@
     }
 
     @Test
-    public void testListener_propertiesCallback() throws InterruptedException {
+    public void testOnPropertiesChangedListener() throws InterruptedException {
         final CountDownLatch countDownLatch = new CountDownLatch(1);
 
-        OnPropertyChangedListener changeListener = new OnPropertyChangedListener() {
-            public void onPropertyChanged(String namespace, String name, String value) {
-                // ignore legacy callback
-            }
-
-            @Override
-            public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                assertThat(properties.getNamespace()).isEqualTo(sNamespace);
-                assertThat(properties.getKeyset().size()).isEqualTo(1);
-                assertThat(properties.getKeyset()).contains(sKey);
-                assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue);
-                countDownLatch.countDown();
-            }
+        OnPropertiesChangedListener changeListener = (properties) -> {
+            assertThat(properties.getNamespace()).isEqualTo(sNamespace);
+            assertThat(properties.getKeyset()).contains(sKey);
+            assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue);
+            countDownLatch.countDown();
         };
 
-        testListener(countDownLatch, changeListener);
+        try {
+            DeviceConfig.addOnPropertiesChangedListener(sNamespace,
+                    ActivityThread.currentApplication().getMainExecutor(), changeListener);
+            DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+            assertThat(countDownLatch.await(
+                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+        } catch (InterruptedException e) {
+            Assert.fail(e.getMessage());
+        } finally {
+            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+        }
     }
 
     @Test
-    public void testListener_legacyCallback() throws InterruptedException {
+    public void testOnPropertyChangedListener() throws InterruptedException {
         CountDownLatch countDownLatch = new CountDownLatch(1);
 
         OnPropertyChangedListener changeListener = (namespace, name, value) -> {
@@ -256,12 +259,6 @@
             countDownLatch.countDown();
         };
 
-        testListener(countDownLatch, changeListener);
-
-    }
-
-    private void testListener(CountDownLatch countDownLatch,
-            OnPropertyChangedListener changeListener) {
         try {
             DeviceConfig.addOnPropertyChangedListener(sNamespace,
                     ActivityThread.currentApplication().getMainExecutor(), changeListener);
@@ -273,6 +270,7 @@
         } finally {
             DeviceConfig.removeOnPropertyChangedListener(changeListener);
         }
+
     }
 
     private static boolean deleteViaContentProvider(String namespace, String key) {
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index c99777b..0f32a82 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -89,6 +89,17 @@
         assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CATEGORY));
     }
 
+    /** Verify that modifying the returned logMaker won't leave stale data behind for
+     * the next caller.*/
+    @Test
+    public void testLogMakerNoStaleData() {
+        StatusBarNotification sbn = getNotification(PKG, GROUP_ID_1, CHANNEL_ID);
+        final LogMaker logMaker = sbn.getLogMaker();
+        int extraTag = MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID;  // An arbitrary new tag
+        logMaker.addTaggedData(extraTag, 1);
+        assertNull(sbn.getLogMaker().getTaggedData(extraTag));
+    }
+
     @Test
     public void testLogMakerWithCategory() {
         Notification.Builder builder = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID)
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
index c6dc239..1e03c53 100644
--- a/graphics/java/android/graphics/Insets.java
+++ b/graphics/java/android/graphics/Insets.java
@@ -30,7 +30,7 @@
  *
  */
 public final class Insets implements Parcelable {
-    public static final Insets NONE = new Insets(0, 0, 0, 0);
+    public static final @NonNull Insets NONE = new Insets(0, 0, 0, 0);
 
     public final int left;
     public final int top;
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 793dd8d..4f1b2a4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -69,6 +69,7 @@
         "libminikin",
         "libandroidfw",
         "libcrypto",
+        "libsync",
     ],
     static_libs: [
         "libEGL_blobCache",
@@ -180,6 +181,7 @@
         "renderthread/EglManager.cpp",
         "renderthread/ReliableSurface.cpp",
         "renderthread/VulkanManager.cpp",
+        "renderthread/VulkanSurface.cpp",
         "renderthread/RenderProxy.cpp",
         "renderthread/RenderTask.cpp",
         "renderthread/RenderThread.cpp",
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index a15ff22..c174c24 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -19,8 +19,6 @@
 #include "renderstate/RenderState.h"
 #include "utils/Color.h"
 
-#include <SkToSRGBColorFilter.h>
-
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 2ffda83..fe633e9 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -20,7 +20,6 @@
 #include "renderthread/EglManager.h"
 #include "renderthread/VulkanManager.h"
 
-#include <SkToSRGBColorFilter.h>
 #include <gui/Surface.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 87cffb5..edde6d3 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -55,20 +55,8 @@
 }
 
 Frame SkiaVulkanPipeline::getFrame() {
-    LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
-                        "drawRenderNode called on a context with no surface!");
-
-    SkSurface* backBuffer = mVkManager.getBackbufferSurface(&mVkSurface);
-    LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
-                        "drawRenderNode called on a context with an invalid surface");
-    if (backBuffer == nullptr) {
-        SkDebugf("failed to get backbuffer");
-        return Frame(-1, -1, 0);
-    }
-
-    Frame frame(mVkSurface->windowWidth(), mVkSurface->windowHeight(),
-                mVkManager.getAge(mVkSurface));
-    return frame;
+    LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
+    return mVkManager.dequeueNextBuffer(mVkSurface);
 }
 
 bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
@@ -77,13 +65,13 @@
                               bool opaque, const LightInfo& lightInfo,
                               const std::vector<sp<RenderNode>>& renderNodes,
                               FrameInfoVisualizer* profiler) {
-    sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
+    sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
     if (backBuffer.get() == nullptr) {
         return false;
     }
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
-            backBuffer, mVkSurface->preTransform());
+            backBuffer, mVkSurface->getCurrentPreTransform());
     ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
     layerUpdateQueue->clear();
 
@@ -113,7 +101,7 @@
     currentFrameInfo->markSwapBuffers();
 
     if (*requireSwap) {
-        mVkManager.swapBuffers(mVkSurface);
+        mVkManager.swapBuffers(mVkSurface, screenDirty);
     }
 
     return *requireSwap;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 2c24edd..77a7ab1 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -18,6 +18,7 @@
 
 #include "SkiaPipeline.h"
 #include "renderthread/VulkanManager.h"
+#include "renderthread/VulkanSurface.h"
 
 #include "renderstate/RenderState.h"
 
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5af660c..d4c6eae 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,6 +16,7 @@
 
 #include "VulkanManager.h"
 
+#include <android/sync.h>
 #include <gui/Surface.h>
 
 #include "Properties.h"
@@ -23,6 +24,7 @@
 #include "renderstate/RenderState.h"
 #include "utils/FatVector.h"
 
+#include <GrBackendSemaphore.h>
 #include <GrBackendSurface.h>
 #include <GrContext.h>
 #include <GrTypes.h>
@@ -142,6 +144,7 @@
     GET_INST_PROC(GetPhysicalDeviceProperties);
     GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
     GET_INST_PROC(GetPhysicalDeviceFeatures2);
+    GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
     GET_INST_PROC(CreateDevice);
     GET_INST_PROC(EnumerateDeviceExtensionProperties);
     GET_INST_PROC(CreateAndroidSurfaceKHR);
@@ -318,11 +321,6 @@
     GET_DEV_PROC(GetDeviceQueue);
     GET_DEV_PROC(DeviceWaitIdle);
     GET_DEV_PROC(DestroyDevice);
-    GET_DEV_PROC(CreateSwapchainKHR);
-    GET_DEV_PROC(DestroySwapchainKHR);
-    GET_DEV_PROC(GetSwapchainImagesKHR);
-    GET_DEV_PROC(AcquireNextImageKHR);
-    GET_DEV_PROC(QueuePresentKHR);
     GET_DEV_PROC(CreateCommandPool);
     GET_DEV_PROC(DestroyCommandPool);
     GET_DEV_PROC(AllocateCommandBuffers);
@@ -426,201 +424,102 @@
     };
 }
 
-// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
-// previous uses have finished before returning.
-VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
-    SkASSERT(surface->mBackbuffers);
+Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
 
-    ++surface->mCurrentBackbufferIndex;
-    if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
-        surface->mCurrentBackbufferIndex = 0;
+    VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
+
+    if (bufferInfo == nullptr) {
+        ALOGE("VulkanSurface::dequeueNativeBuffer called with an invalid surface!");
+        return Frame(-1, -1, 0);
     }
 
-    VulkanSurface::BackbufferInfo* backbuffer =
-            surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+    LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
 
-    // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
-    // reuse its commands buffers.
-    VkResult res = mWaitForFences(mDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
-    if (res != VK_SUCCESS) {
-        return nullptr;
+    if (bufferInfo->dequeue_fence != -1) {
+        int fence_clone = dup(bufferInfo->dequeue_fence);
+        if (fence_clone == -1) {
+            ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno);
+            sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+        } else {
+            VkSemaphoreCreateInfo semaphoreInfo;
+            semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+            semaphoreInfo.pNext = nullptr;
+            semaphoreInfo.flags = 0;
+            VkSemaphore semaphore;
+            VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+            LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
+                                err);
+
+            VkImportSemaphoreFdInfoKHR importInfo;
+            importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+            importInfo.pNext = nullptr;
+            importInfo.semaphore = semaphore;
+            importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+            importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+            importInfo.fd = fence_clone;
+
+            err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+            LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
+
+            GrBackendSemaphore backendSemaphore;
+            backendSemaphore.initVulkan(semaphore);
+            bufferInfo->skSurface->wait(1, &backendSemaphore);
+        }
     }
 
-    return backbuffer;
+    int bufferAge = (mSwapBehavior == SwapBehavior::Discard) ? 0 : surface->getCurrentBuffersAge();
+    return Frame(surface->logicalWidth(), surface->logicalHeight(), bufferAge);
 }
 
-static SkMatrix getPreTransformMatrix(int width, int height,
-                                      VkSurfaceTransformFlagBitsKHR transform) {
-    switch (transform) {
-        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
-            return SkMatrix::I();
-        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
-            return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
-            return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
-            return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
-            return SkMatrix::MakeAll(-1, 0, width, 0, 1, 0, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
-            return SkMatrix::MakeAll(0, -1, height, -1, 0, width, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
-            return SkMatrix::MakeAll(1, 0, 0, 0, -1, height, 0, 0, 1);
-        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
-            return SkMatrix::MakeAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
-        default:
-            LOG_ALWAYS_FATAL("Unsupported pre transform of swapchain.");
-    }
-    return SkMatrix::I();
-}
-
-
-SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
-    // Recreate VulkanSurface, if ANativeWindow has been resized.
-    VulkanSurface* surface = *surfaceOut;
-    int windowWidth = 0, windowHeight = 0;
-    ANativeWindow* window = surface->mNativeWindow;
-    window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
-    window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
-    if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
-        ColorMode colorMode = surface->mColorMode;
-        sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
-        SkColorType colorType = surface->mColorType;
-        GrContext* grContext = surface->mGrContext;
-        destroySurface(surface);
-        *surfaceOut = createSurface(window, colorMode, colorSpace, colorType, grContext);
-        surface = *surfaceOut;
-        if (!surface) {
-            return nullptr;
-        }
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+        ATRACE_NAME("Finishing GPU work");
+        mDeviceWaitIdle(mDevice);
     }
 
-    VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
-    SkASSERT(backbuffer);
+    VkExportSemaphoreCreateInfo exportInfo;
+    exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+    exportInfo.pNext = nullptr;
+    exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
 
-    VkResult res;
+    VkSemaphoreCreateInfo semaphoreInfo;
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = &exportInfo;
+    semaphoreInfo.flags = 0;
+    VkSemaphore semaphore;
+    VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+    ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
 
-    res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
-    SkASSERT(VK_SUCCESS == res);
+    GrBackendSemaphore backendSemaphore;
+    backendSemaphore.initVulkan(semaphore);
 
-    // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
-    // finished presenting and that it is safe to begin sending new commands to the returned image.
-    res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
-                               backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
-                               &backbuffer->mImageIndex);
+    VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
 
-    if (VK_ERROR_SURFACE_LOST_KHR == res) {
-        // need to figure out how to create a new vkSurface without the platformData*
-        // maybe use attach somehow? but need a Window
-        return nullptr;
-    }
-    if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_SUBOPTIMAL_KHR == res) {
-        // tear swapchain down and try again
-        if (!createSwapchain(surface)) {
-            return nullptr;
-        }
-        backbuffer = getAvailableBackbuffer(surface);
-        res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
-        SkASSERT(VK_SUCCESS == res);
+    int fenceFd = -1;
+    GrSemaphoresSubmitted submitted =
+            bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent,
+                                         SkSurface::kNone_FlushFlags, 1, &backendSemaphore);
+    if (submitted == GrSemaphoresSubmitted::kYes) {
+        VkSemaphoreGetFdInfoKHR getFdInfo;
+        getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+        getFdInfo.pNext = nullptr;
+        getFdInfo.semaphore = semaphore;
+        getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
 
-        // acquire the image
-        res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
-                                   backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
-                                   &backbuffer->mImageIndex);
-
-        if (VK_SUCCESS != res) {
-            return nullptr;
-        }
+        err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+        ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
+    } else {
+        ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+        mQueueWaitIdle(mGraphicsQueue);
     }
 
-    // set up layout transfer from initial to color attachment
-    VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
-    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
-    VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    VkAccessFlags srcAccessMask = 0;
-    VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-                                  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    surface->presentCurrentBuffer(dirtyRect, fenceFd);
 
-    VkImageMemoryBarrier imageMemoryBarrier = {
-            VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     // sType
-            NULL,                                       // pNext
-            srcAccessMask,                              // outputMask
-            dstAccessMask,                              // inputMask
-            layout,                                     // oldLayout
-            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   // newLayout
-            mPresentQueueIndex,                         // srcQueueFamilyIndex
-            mGraphicsQueueIndex,       // dstQueueFamilyIndex
-            surface->mImages[backbuffer->mImageIndex],  // image
-            {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}     // subresourceRange
-    };
-    mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
-
-    VkCommandBufferBeginInfo info;
-    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
-    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-    info.flags = 0;
-    mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
-
-    mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
-                        nullptr, 0, nullptr, 1, &imageMemoryBarrier);
-
-    mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
-
-    VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    // insert the layout transfer into the queue and wait on the acquire
-    VkSubmitInfo submitInfo;
-    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-    submitInfo.waitSemaphoreCount = 1;
-    // Wait to make sure aquire semaphore set above has signaled.
-    submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
-    submitInfo.pWaitDstStageMask = &waitDstStageFlags;
-    submitInfo.commandBufferCount = 1;
-    submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
-    submitInfo.signalSemaphoreCount = 0;
-
-    // Attach first fence to submission here so we can track when the command buffer finishes.
-    mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
-
-    // We need to notify Skia that we changed the layout of the wrapped VkImage
-    sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
-    GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
-            SkSurface::kFlushRead_BackendHandleAccess);
-    if (!backendRT.isValid()) {
-        SkASSERT(backendRT.isValid());
-        return nullptr;
-    }
-    backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
-    surface->mPreTransform = getPreTransformMatrix(surface->windowWidth(),
-                                                   surface->windowHeight(),
-                                                   surface->mTransform);
-
-    surface->mBackbuffer = std::move(skSurface);
-    return surface->mBackbuffer.get();
-}
-
-void VulkanManager::destroyBuffers(VulkanSurface* surface) {
-    if (surface->mBackbuffers) {
-        for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
-            mWaitForFences(mDevice, 2, surface->mBackbuffers[i].mUsageFences, true, UINT64_MAX);
-            surface->mBackbuffers[i].mImageIndex = -1;
-            mDestroySemaphore(mDevice, surface->mBackbuffers[i].mAcquireSemaphore, nullptr);
-            mDestroySemaphore(mDevice, surface->mBackbuffers[i].mRenderSemaphore, nullptr);
-            mFreeCommandBuffers(mDevice, mCommandPool, 2,
-                    surface->mBackbuffers[i].mTransitionCmdBuffers);
-            mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
-            mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
-        }
-    }
-
-    delete[] surface->mBackbuffers;
-    surface->mBackbuffers = nullptr;
-    delete[] surface->mImageInfos;
-    surface->mImageInfos = nullptr;
-    delete[] surface->mImages;
-    surface->mImages = nullptr;
+    // Exporting a semaphore with copy transference via vkGetSemaphoreFdKHR, has the same effect of
+    // destroying the semaphore and creating a new one with the same handle, and the payloads
+    // ownership is move to the Fd we created. Thus the semaphore is in a state that we can delete
+    // it and we don't need to wait on the command buffer we submitted to finish.
+    mDestroySemaphore(mDevice, semaphore, nullptr);
 }
 
 void VulkanManager::destroySurface(VulkanSurface* surface) {
@@ -630,271 +529,9 @@
     }
     mDeviceWaitIdle(mDevice);
 
-    destroyBuffers(surface);
-
-    if (VK_NULL_HANDLE != surface->mSwapchain) {
-        mDestroySwapchainKHR(mDevice, surface->mSwapchain, nullptr);
-        surface->mSwapchain = VK_NULL_HANDLE;
-    }
-
-    if (VK_NULL_HANDLE != surface->mVkSurface) {
-        mDestroySurfaceKHR(mInstance, surface->mVkSurface, nullptr);
-        surface->mVkSurface = VK_NULL_HANDLE;
-    }
     delete surface;
 }
 
-void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
-    mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, nullptr);
-    SkASSERT(surface->mImageCount);
-    surface->mImages = new VkImage[surface->mImageCount];
-    mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, surface->mImages);
-
-    SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
-
-    // set up initial image layouts and create surfaces
-    surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
-    for (uint32_t i = 0; i < surface->mImageCount; ++i) {
-        GrVkImageInfo info;
-        info.fImage = surface->mImages[i];
-        info.fAlloc = GrVkAlloc();
-        info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-        info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-        info.fFormat = format;
-        info.fLevelCount = 1;
-
-        GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
-
-        VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
-        imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
-                surface->mGrContext, backendRT, kTopLeft_GrSurfaceOrigin,
-                surface->mColorType, surface->mColorSpace, &props);
-    }
-
-    SkASSERT(mCommandPool != VK_NULL_HANDLE);
-
-    // set up the backbuffers
-    VkSemaphoreCreateInfo semaphoreInfo;
-    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
-    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-    semaphoreInfo.pNext = nullptr;
-    semaphoreInfo.flags = 0;
-    VkCommandBufferAllocateInfo commandBuffersInfo;
-    memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
-    commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-    commandBuffersInfo.pNext = nullptr;
-    commandBuffersInfo.commandPool = mCommandPool;
-    commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-    commandBuffersInfo.commandBufferCount = 2;
-    VkFenceCreateInfo fenceInfo;
-    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
-    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-    fenceInfo.pNext = nullptr;
-    fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
-    // we create one additional backbuffer structure here, because we want to
-    // give the command buffers they contain a chance to finish before we cycle back
-    surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
-    for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
-        SkDEBUGCODE(VkResult res);
-        surface->mBackbuffers[i].mImageIndex = -1;
-        SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
-                                            &surface->mBackbuffers[i].mAcquireSemaphore);
-        SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
-                                            &surface->mBackbuffers[i].mRenderSemaphore);
-        SkDEBUGCODE(res =) mAllocateCommandBuffers(mDevice, &commandBuffersInfo,
-                                                   surface->mBackbuffers[i].mTransitionCmdBuffers);
-        SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
-                                        &surface->mBackbuffers[i].mUsageFences[0]);
-        SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
-                                        &surface->mBackbuffers[i].mUsageFences[1]);
-        SkASSERT(VK_SUCCESS == res);
-    }
-    surface->mCurrentBackbufferIndex = surface->mImageCount;
-}
-
-bool VulkanManager::createSwapchain(VulkanSurface* surface) {
-    // check for capabilities
-    VkSurfaceCapabilitiesKHR caps;
-    VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDevice,
-                                                            surface->mVkSurface, &caps);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    uint32_t surfaceFormatCount;
-    res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
-                                              &surfaceFormatCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
-    res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
-                                              &surfaceFormatCount, surfaceFormats.data());
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    uint32_t presentModeCount;
-    res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
-                                                   surface->mVkSurface, &presentModeCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
-    res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
-                                                   surface->mVkSurface, &presentModeCount,
-                                                   presentModes.data());
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    if (!SkToBool(caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) {
-        return false;
-    }
-    VkSurfaceTransformFlagBitsKHR transform;
-    if (SkToBool(caps.supportedTransforms & caps.currentTransform) &&
-        !SkToBool(caps.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) {
-        transform = caps.currentTransform;
-    } else {
-        transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-    }
-
-    VkExtent2D extent = caps.currentExtent;
-    // clamp width; to handle currentExtent of -1 and  protect us from broken hints
-    if (extent.width < caps.minImageExtent.width) {
-        extent.width = caps.minImageExtent.width;
-    }
-    SkASSERT(extent.width <= caps.maxImageExtent.width);
-    // clamp height
-    if (extent.height < caps.minImageExtent.height) {
-        extent.height = caps.minImageExtent.height;
-    }
-    SkASSERT(extent.height <= caps.maxImageExtent.height);
-
-    VkExtent2D swapExtent = extent;
-    if (transform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
-        transform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR ||
-        transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR ||
-        transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
-        swapExtent.width = extent.height;
-        swapExtent.height = extent.width;
-    }
-
-    surface->mWindowWidth = extent.width;
-    surface->mWindowHeight = extent.height;
-
-    uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
-    if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
-        // Application must settle for fewer images than desired:
-        imageCount = caps.maxImageCount;
-    }
-
-    // Currently Skia requires the images to be color attchments and support all transfer
-    // operations.
-    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
-                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-    SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-
-    SkASSERT(caps.supportedCompositeAlpha &
-             (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
-    VkCompositeAlphaFlagBitsKHR composite_alpha =
-            (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
-                    ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
-                    : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
-    VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
-    VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
-    if (surface->mColorType == SkColorType::kRGBA_F16_SkColorType) {
-        surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
-    }
-
-    if (surface->mColorMode == ColorMode::WideColorGamut) {
-        skcms_Matrix3x3 surfaceGamut;
-        LOG_ALWAYS_FATAL_IF(!surface->mColorSpace->toXYZD50(&surfaceGamut),
-                            "Could not get gamut matrix from color space");
-        if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
-            colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
-        } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
-            colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
-        } else {
-            LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
-        }
-    }
-
-    bool foundSurfaceFormat = false;
-    for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
-        if (surfaceFormat == surfaceFormats[i].format
-                && colorSpace == surfaceFormats[i].colorSpace) {
-            foundSurfaceFormat = true;
-            break;
-        }
-    }
-
-    if (!foundSurfaceFormat) {
-        return false;
-    }
-
-    // FIFO is always available and will match what we do on GL so just pick that here.
-    VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-
-    VkSwapchainCreateInfoKHR swapchainCreateInfo;
-    memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
-    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
-    swapchainCreateInfo.surface = surface->mVkSurface;
-    swapchainCreateInfo.minImageCount = imageCount;
-    swapchainCreateInfo.imageFormat = surfaceFormat;
-    swapchainCreateInfo.imageColorSpace = colorSpace;
-    swapchainCreateInfo.imageExtent = swapExtent;
-    swapchainCreateInfo.imageArrayLayers = 1;
-    swapchainCreateInfo.imageUsage = usageFlags;
-
-    uint32_t queueFamilies[] = {mGraphicsQueueIndex, mPresentQueueIndex};
-    if (mGraphicsQueueIndex != mPresentQueueIndex) {
-        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
-        swapchainCreateInfo.queueFamilyIndexCount = 2;
-        swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
-    } else {
-        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
-        swapchainCreateInfo.queueFamilyIndexCount = 0;
-        swapchainCreateInfo.pQueueFamilyIndices = nullptr;
-    }
-
-    swapchainCreateInfo.preTransform = transform;
-    swapchainCreateInfo.compositeAlpha = composite_alpha;
-    swapchainCreateInfo.presentMode = mode;
-    swapchainCreateInfo.clipped = true;
-    swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
-
-    res = mCreateSwapchainKHR(mDevice, &swapchainCreateInfo, nullptr, &surface->mSwapchain);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    surface->mTransform = transform;
-
-    // destroy the old swapchain
-    if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
-        mDeviceWaitIdle(mDevice);
-
-        destroyBuffers(surface);
-
-        mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
-    }
-
-    createBuffers(surface, surfaceFormat, swapExtent);
-
-    // The window content is not updated (frozen) until a buffer of the window size is received.
-    // This prevents temporary stretching of the window after it is resized, but before the first
-    // buffer with new size is enqueued.
-    native_window_set_scaling_mode(surface->mNativeWindow, NATIVE_WINDOW_SCALING_MODE_FREEZE);
-
-    return true;
-}
-
 VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
                                             sk_sp<SkColorSpace> surfaceColorSpace,
                                             SkColorType surfaceColorType,
@@ -904,185 +541,8 @@
         return nullptr;
     }
 
-    VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
-                                               surfaceColorType, grContext);
-
-    VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
-    memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
-    surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
-    surfaceCreateInfo.pNext = nullptr;
-    surfaceCreateInfo.flags = 0;
-    surfaceCreateInfo.window = window;
-
-    VkResult res = mCreateAndroidSurfaceKHR(mInstance, &surfaceCreateInfo, nullptr,
-            &surface->mVkSurface);
-    if (VK_SUCCESS != res) {
-        delete surface;
-        return nullptr;
-    }
-
-    SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
-            mPhysicalDevice, mPresentQueueIndex, surface->mVkSurface, &supported);
-    // All physical devices and queue families on Android must be capable of
-    // presentation with any native window.
-    SkASSERT(VK_SUCCESS == res && supported););
-
-    if (!createSwapchain(surface)) {
-        destroySurface(surface);
-        return nullptr;
-    }
-
-    return surface;
-}
-
-// Helper to know which src stage flags we need to set when transitioning to the present layout
-static VkPipelineStageFlags layoutToPipelineSrcStageFlags(const VkImageLayout layout) {
-    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
-        return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
-    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
-               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
-        return VK_PIPELINE_STAGE_TRANSFER_BIT;
-    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
-        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
-               VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
-        return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
-        return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
-        return VK_PIPELINE_STAGE_HOST_BIT;
-    }
-
-    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
-    return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-}
-
-// Helper to know which src access mask we need to set when transitioning to the present layout
-static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
-    VkAccessFlags flags = 0;
-    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
-        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
-                VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
-                VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
-                VK_ACCESS_HOST_READ_BIT;
-    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
-        flags = VK_ACCESS_HOST_WRITE_BIT;
-    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
-        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
-        flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-    } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
-        flags = VK_ACCESS_TRANSFER_WRITE_BIT;
-    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
-        flags = VK_ACCESS_TRANSFER_READ_BIT;
-    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
-        flags = VK_ACCESS_SHADER_READ_BIT;
-    }
-    return flags;
-}
-
-void VulkanManager::swapBuffers(VulkanSurface* surface) {
-    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
-        ATRACE_NAME("Finishing GPU work");
-        mDeviceWaitIdle(mDevice);
-    }
-
-    SkASSERT(surface->mBackbuffers);
-    VulkanSurface::BackbufferInfo* backbuffer =
-            surface->mBackbuffers + surface->mCurrentBackbufferIndex;
-
-    SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
-    GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
-            SkSurface::kFlushRead_BackendHandleAccess);
-    SkASSERT(backendRT.isValid());
-
-    GrVkImageInfo imageInfo;
-    SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
-
-    // Check to make sure we never change the actually wrapped image
-    SkASSERT(imageInfo.fImage == surface->mImages[backbuffer->mImageIndex]);
-
-    // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
-    // previous work is complete for before presenting. So we first add the necessary barrier here.
-    VkImageLayout layout = imageInfo.fImageLayout;
-    VkPipelineStageFlags srcStageMask = layoutToPipelineSrcStageFlags(layout);
-    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-    VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
-    VkAccessFlags dstAccessMask = 0;
-
-    VkImageMemoryBarrier imageMemoryBarrier = {
-            VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     // sType
-            NULL,                                       // pNext
-            srcAccessMask,                              // outputMask
-            dstAccessMask,                              // inputMask
-            layout,                                     // oldLayout
-            VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,            // newLayout
-            mGraphicsQueueIndex,                        // srcQueueFamilyIndex
-            mPresentQueueIndex,                         // dstQueueFamilyIndex
-            surface->mImages[backbuffer->mImageIndex],  // image
-            {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}     // subresourceRange
-    };
-
-    mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
-    VkCommandBufferBeginInfo info;
-    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
-    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-    info.flags = 0;
-    mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
-    mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
-                        nullptr, 0, nullptr, 1, &imageMemoryBarrier);
-    mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
-
-    surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
-    // insert the layout transfer into the queue and wait on the acquire
-    VkSubmitInfo submitInfo;
-    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-    submitInfo.waitSemaphoreCount = 0;
-    submitInfo.pWaitDstStageMask = 0;
-    submitInfo.commandBufferCount = 1;
-    submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
-    submitInfo.signalSemaphoreCount = 1;
-    // When this command buffer finishes we will signal this semaphore so that we know it is now
-    // safe to present the image to the screen.
-    submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
-
-    // Attach second fence to submission here so we can track when the command buffer finishes.
-    mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
-
-    // Submit present operation to present queue. We use a semaphore here to make sure all rendering
-    // to the image is complete and that the layout has been change to present on the graphics
-    // queue.
-    const VkPresentInfoKHR presentInfo = {
-            VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,  // sType
-            NULL,                                // pNext
-            1,                                   // waitSemaphoreCount
-            &backbuffer->mRenderSemaphore,       // pWaitSemaphores
-            1,                                   // swapchainCount
-            &surface->mSwapchain,                // pSwapchains
-            &backbuffer->mImageIndex,            // pImageIndices
-            NULL                                 // pResults
-    };
-
-    mQueuePresentKHR(mPresentQueue, &presentInfo);
-
-    surface->mBackbuffer.reset();
-    surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
-    surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
-    surface->mCurrentTime++;
-}
-
-int VulkanManager::getAge(VulkanSurface* surface) {
-    SkASSERT(surface->mBackbuffers);
-    VulkanSurface::BackbufferInfo* backbuffer =
-            surface->mBackbuffers + surface->mCurrentBackbufferIndex;
-    if (mSwapBehavior == SwapBehavior::Discard ||
-        surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
-        return 0;
-    }
-    uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
-    return surface->mCurrentTime - lastUsed;
+    return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext,
+                                  *this);
 }
 
 bool VulkanManager::setupDummyCommandBuffer() {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 95c9630..c3d2891 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -28,7 +28,9 @@
 #include <ui/Fence.h>
 #include <utils/StrongPointer.h>
 #include <vk/GrVkBackendContext.h>
+#include "Frame.h"
 #include "IRenderPipeline.h"
+#include "VulkanSurface.h"
 
 class GrVkExtensions;
 
@@ -38,66 +40,6 @@
 
 class RenderThread;
 
-class VulkanSurface {
-public:
-    VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
-                  SkColorType colorType, GrContext* grContext)
-            : mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
-              mColorType(colorType), mGrContext(grContext) {}
-
-    sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
-
-    // The width and height are are the logical width and height for when submitting draws to the
-    // surface. In reality if the window is rotated the underlying VkImage may have the width and
-    // height swapped.
-    int windowWidth() const { return mWindowWidth; }
-    int windowHeight() const { return mWindowHeight; }
-
-    SkMatrix& preTransform() { return mPreTransform; }
-
-private:
-    friend class VulkanManager;
-    struct BackbufferInfo {
-        uint32_t mImageIndex;           // image this is associated with
-        VkSemaphore mAcquireSemaphore;  // we signal on this for acquisition of image
-        VkSemaphore mRenderSemaphore;   // we wait on this for rendering to be done
-        VkCommandBuffer
-                mTransitionCmdBuffers[2];  // to transition layout between present and render
-        // We use these fences to make sure the above Command buffers have finished their work
-        // before attempting to reuse them or destroy them.
-        VkFence mUsageFences[2];
-    };
-
-    struct ImageInfo {
-        VkImageLayout mImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-        sk_sp<SkSurface> mSurface;
-        uint16_t mLastUsed = 0;
-        bool mInvalid = true;
-    };
-
-    sk_sp<SkSurface> mBackbuffer;
-
-    VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
-    VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
-
-    BackbufferInfo* mBackbuffers = nullptr;
-    uint32_t mCurrentBackbufferIndex;
-
-    uint32_t mImageCount;
-    VkImage* mImages = nullptr;
-    ImageInfo* mImageInfos;
-    uint16_t mCurrentTime = 0;
-    ColorMode mColorMode;
-    ANativeWindow* mNativeWindow;
-    int mWindowWidth = 0;
-    int mWindowHeight = 0;
-    sk_sp<SkColorSpace> mColorSpace;
-    SkColorType mColorType;
-    VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-    SkMatrix mPreTransform;
-    GrContext* mGrContext;
-};
-
 // This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
 // which are re-used by CanvasContext. This class is created once and should be used by all vulkan
 // windowing contexts. The VulkanManager must be initialized before use.
@@ -114,33 +56,19 @@
     // Quick check to see if the VulkanManager has been initialized.
     bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
 
-    // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
-    // VulkanSurface object which is returned.
+    // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
     VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
                                  sk_sp<SkColorSpace> surfaceColorSpace,
                                  SkColorType surfaceColorType,
                                  GrContext* grContext);
-
-    // Destroy the VulkanSurface and all associated vulkan objects.
     void destroySurface(VulkanSurface* surface);
 
+    Frame dequeueNextBuffer(VulkanSurface* surface);
+    void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
+
     // Cleans up all the global state in the VulkanManger.
     void destroy();
 
-    // No work is needed to make a VulkanSurface current, and all functions require that a
-    // VulkanSurface is passed into them so we just return true here.
-    bool isCurrent(VulkanSurface* surface) { return true; }
-
-    int getAge(VulkanSurface* surface);
-
-    // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also
-    // will transition the VkImage from a present layout to color attachment so that it can be used
-    // by the client for drawing.
-    SkSurface* getBackbufferSurface(VulkanSurface** surface);
-
-    // Presents the current VkImage.
-    void swapBuffers(VulkanSurface* surface);
-
     // Inserts a wait on fence command into the Vulkan command buffer.
     status_t fenceWait(sp<Fence>& fence);
 
@@ -153,17 +81,10 @@
     sk_sp<GrContext> createContext(const GrContextOptions& options);
 
 private:
+    friend class VulkanSurface;
     // Sets up the VkInstance and VkDevice objects. Also fills out the passed in
     // VkPhysicalDeviceFeatures struct.
     void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
-
-    void destroyBuffers(VulkanSurface* surface);
-
-    bool createSwapchain(VulkanSurface* surface);
-    void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent);
-
-    VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
-
     bool setupDummyCommandBuffer();
 
     // simple wrapper class that exists only to initialize a pointer to NULL
@@ -190,13 +111,6 @@
     VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR;
     VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR;
 
-    VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR;
-    VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR;
-    VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR;
-    VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR;
-    VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
-    VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
-
     // Instance Functions
     VkPtr<PFN_vkEnumerateInstanceVersion> mEnumerateInstanceVersion;
     VkPtr<PFN_vkEnumerateInstanceExtensionProperties> mEnumerateInstanceExtensionProperties;
@@ -207,6 +121,7 @@
     VkPtr<PFN_vkGetPhysicalDeviceProperties> mGetPhysicalDeviceProperties;
     VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
     VkPtr<PFN_vkGetPhysicalDeviceFeatures2> mGetPhysicalDeviceFeatures2;
+    VkPtr<PFN_vkGetPhysicalDeviceImageFormatProperties2> mGetPhysicalDeviceImageFormatProperties2;
     VkPtr<PFN_vkCreateDevice> mCreateDevice;
     VkPtr<PFN_vkEnumerateDeviceExtensionProperties> mEnumerateDeviceExtensionProperties;
 
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
new file mode 100644
index 0000000..c03c3a8
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VulkanSurface.h"
+
+#include <algorithm>
+#include <SkSurface.h>
+
+#include "VulkanManager.h"
+#include "utils/TraceUtils.h"
+#include "utils/Color.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+static bool IsTransformSupported(int transform) {
+    // For now, only support pure rotations, not flip or flip-and-rotate, until we have
+    // more time to test them and build sample code. As far as I know we never actually
+    // use anything besides pure rotations anyway.
+    return transform == 0
+        || transform == NATIVE_WINDOW_TRANSFORM_ROT_90
+        || transform == NATIVE_WINDOW_TRANSFORM_ROT_180
+        || transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
+}
+
+static int InvertTransform(int transform) {
+    switch (transform) {
+        case NATIVE_WINDOW_TRANSFORM_ROT_90:
+            return NATIVE_WINDOW_TRANSFORM_ROT_270;
+        case NATIVE_WINDOW_TRANSFORM_ROT_180:
+            return NATIVE_WINDOW_TRANSFORM_ROT_180;
+        case NATIVE_WINDOW_TRANSFORM_ROT_270:
+            return NATIVE_WINDOW_TRANSFORM_ROT_90;
+        default:
+            return 0;
+    }
+}
+
+static int ConvertVkTransformToNative(VkSurfaceTransformFlagsKHR transform) {
+    switch (transform) {
+        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_270;
+        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_180;
+        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+            return NATIVE_WINDOW_TRANSFORM_ROT_90;
+        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+        case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+        default:
+            return 0;
+    }
+}
+
+static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
+    const int width = windowSize.width();
+    const int height = windowSize.height();
+
+    switch (transform) {
+        case 0:
+            return SkMatrix::I();
+        case NATIVE_WINDOW_TRANSFORM_ROT_90:
+            return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
+        case NATIVE_WINDOW_TRANSFORM_ROT_180:
+            return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
+        case NATIVE_WINDOW_TRANSFORM_ROT_270:
+            return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
+        default:
+            LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
+    }
+    return SkMatrix::I();
+}
+
+void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
+                                                   const SkISize& maxSize) {
+    SkISize& windowSize = windowInfo->size;
+
+    // clamp width & height to handle currentExtent of -1 and  protect us from broken hints
+    if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width()
+        || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
+        int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
+        int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
+        ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]",
+              windowSize.width(), windowSize.height(), width, height);
+        windowSize.set(width, height);
+    }
+
+    windowInfo->actualSize = windowSize;
+    if (windowInfo->transform & HAL_TRANSFORM_ROT_90) {
+        windowInfo->actualSize.set(windowSize.height(), windowSize.width());
+    }
+
+    windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
+}
+
+static bool ResetNativeWindow(ANativeWindow* window) {
+    // -- Reset the native window --
+    // The native window might have been used previously, and had its properties
+    // changed from defaults. That will affect the answer we get for queries
+    // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we
+    // attempt such queries.
+
+    int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+    if (err != 0) {
+        ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err);
+        return false;
+    }
+
+    // this will match what we do on GL so pick that here.
+    err = window->setSwapInterval(window, 1);
+    if (err != 0) {
+        ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
+        return false;
+    }
+
+    err = native_window_set_shared_buffer_mode(window, false);
+    if (err != 0) {
+        ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
+        return false;
+    }
+
+    err = native_window_set_auto_refresh(window, false);
+    if (err != 0) {
+        ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
+        return false;
+    }
+
+    return true;
+}
+
+class VkSurfaceAutoDeleter {
+public:
+    VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface,
+                         PFN_vkDestroySurfaceKHR destroySurfaceKHR)
+            : mInstance(instance)
+            , mSurface(surface)
+            , mDestroySurfaceKHR(destroySurfaceKHR) {}
+    ~VkSurfaceAutoDeleter() {
+        destroy();
+    }
+
+    void destroy() {
+        if (mSurface != VK_NULL_HANDLE) {
+            mDestroySurfaceKHR(mInstance, mSurface, nullptr);
+            mSurface = VK_NULL_HANDLE;
+        }
+    }
+
+private:
+    VkInstance mInstance;
+    VkSurfaceKHR mSurface;
+    PFN_vkDestroySurfaceKHR mDestroySurfaceKHR;
+};
+
+VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
+                                       SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
+                                       GrContext* grContext, const VulkanManager& vkManager) {
+
+    VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+    memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+    surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+    surfaceCreateInfo.pNext = nullptr;
+    surfaceCreateInfo.flags = 0;
+    surfaceCreateInfo.window = window;
+
+    VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+    VkResult res = vkManager.mCreateAndroidSurfaceKHR(vkManager.mInstance, &surfaceCreateInfo,
+                                                      nullptr, &vkSurface);
+    if (VK_SUCCESS != res) {
+        ALOGE("VulkanSurface::Create() vkCreateAndroidSurfaceKHR failed (%d)", res);
+        return nullptr;
+    }
+
+    VkSurfaceAutoDeleter vkSurfaceDeleter(vkManager.mInstance, vkSurface,
+                                          vkManager.mDestroySurfaceKHR);
+
+    SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR(
+            vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported);
+    // All physical devices and queue families on Android must be capable of
+    // presentation with any native window.
+    SkASSERT(VK_SUCCESS == res && supported););
+
+    // check for capabilities
+    VkSurfaceCapabilitiesKHR caps;
+    res = vkManager.mGetPhysicalDeviceSurfaceCapabilitiesKHR(vkManager.mPhysicalDevice, vkSurface,
+                                                             &caps);
+    if (VK_SUCCESS != res) {
+        ALOGE("VulkanSurface::Create() vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed (%d)", res);
+        return nullptr;
+    }
+
+    LOG_ALWAYS_FATAL_IF(0 == (caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR));
+
+    /*
+     * We must destroy the VK Surface before attempting to update the window as doing so after
+     * will cause the native window to be modified in unexpected ways.
+     */
+    vkSurfaceDeleter.destroy();
+
+    /*
+     * Populate Window Info struct
+     */
+    WindowInfo windowInfo;
+
+    windowInfo.transform = ConvertVkTransformToNative(caps.supportedTransforms);
+    windowInfo.size = SkISize::Make(caps.currentExtent.width, caps.currentExtent.height);
+
+    const SkISize minSize = SkISize::Make(caps.minImageExtent.width, caps.minImageExtent.height);
+    const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height);
+    ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
+
+    windowInfo.bufferCount = std::max<uint32_t>(VulkanSurface::sMaxBufferCount, caps.minImageCount);
+    if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
+        // Application must settle for fewer images than desired:
+        windowInfo.bufferCount = caps.maxImageCount;
+    }
+
+    // Currently Skia requires the images to be color attachments and support all transfer
+    // operations.
+    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                                   VK_IMAGE_USAGE_SAMPLED_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
+
+    windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
+    if (colorMode == ColorMode::WideColorGamut) {
+        skcms_Matrix3x3 surfaceGamut;
+        LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
+                            "Could not get gamut matrix from color space");
+        if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
+            windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
+        } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
+            windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
+        } else {
+            LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+        }
+    }
+
+    windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
+    VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
+    if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
+        vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
+    }
+
+    uint64_t producerUsage =
+            AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    uint64_t consumerUsage;
+    native_window_get_consumer_usage(window, &consumerUsage);
+    windowInfo.windowUsageFlags = consumerUsage | producerUsage;
+
+    /*
+     * Now we attempt to modify the window!
+     */
+    if (!UpdateWindow(window, windowInfo)) {
+        return nullptr;
+    }
+
+    return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
+}
+
+bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
+    ATRACE_CALL();
+
+    if (!ResetNativeWindow(window)) {
+        return false;
+    }
+
+    // -- Configure the native window --
+    int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
+              windowInfo.pixelFormat, strerror(-err), err);
+        return false;
+    }
+
+    err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
+              "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err);
+        return false;
+    }
+
+    const SkISize& size = windowInfo.actualSize;
+    err = native_window_set_buffers_dimensions(window, size.width(), size.height());
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
+              "failed: %s (%d)", size.width(), size.height(), strerror(-err), err);
+        return false;
+    }
+
+    // native_window_set_buffers_transform() expects the transform the app is requesting that
+    // the compositor perform during composition. With native windows, pre-transform works by
+    // rendering with the same transform the compositor is applying (as in Vulkan), but
+    // then requesting the inverse transform, so that when the compositor does
+    // it's job the two transforms cancel each other out and the compositor ends
+    // up applying an identity transform to the app's buffer.
+    err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
+              "failed: %s (%d)", windowInfo.transform, strerror(-err), err);
+        return false;
+    }
+
+    // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
+    // HWUI's expectation
+    err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
+              "failed: %s (%d)", strerror(-err), err);
+        return false;
+    }
+
+    // Lower layer insists that we have at least two buffers.
+    err = native_window_set_buffer_count(window, std::max(2, windowInfo.bufferCount));
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%d) failed: %s (%d)",
+              windowInfo.bufferCount, strerror(-err), err);
+        return false;
+    }
+
+    err = native_window_set_usage(window, windowInfo.windowUsageFlags);
+    if (err != 0) {
+        ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
+              strerror(-err), err);
+        return false;
+    }
+
+    return err == 0;
+}
+
+VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
+                               SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
+        : mNativeWindow(window)
+        , mWindowInfo(windowInfo)
+        , mGrContext(grContext)
+        , mMinWindowSize(minWindowSize)
+        , mMaxWindowSize(maxWindowSize) { }
+
+VulkanSurface::~VulkanSurface() {
+    releaseBuffers();
+
+    // release the native window to be available for use by other clients
+    int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
+    ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
+}
+
+void VulkanSurface::releaseBuffers() {
+    for (uint32_t i = 0; i < VulkanSurface::sMaxBufferCount; i++) {
+        VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
+
+        if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
+            int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
+                                                  bufferInfo.dequeue_fence);
+            if (err != 0) {
+                ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
+            }
+            bufferInfo.dequeued = false;
+
+            if (bufferInfo.dequeue_fence >= 0) {
+                close(bufferInfo.dequeue_fence);
+                bufferInfo.dequeue_fence = -1;
+            }
+        }
+
+        LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
+        LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
+
+        bufferInfo.skSurface.reset();
+        bufferInfo.buffer.clear();
+        bufferInfo.hasValidContents = false;
+        bufferInfo.lastPresentedCount = 0;
+    }
+}
+
+VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
+    // Set the dequeue index to invalid in case of error and only reset it to the correct
+    // value at the end of the function if everything dequeued correctly.
+    mDequeuedIndex = -1;
+
+    //check if the native window has been resized or rotated and update accordingly
+    SkISize newSize = SkISize::MakeEmpty();
+    int transformHint = 0;
+    mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
+    mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
+    mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+    if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
+        WindowInfo newWindowInfo = mWindowInfo;
+        newWindowInfo.size = newSize;
+        newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
+        ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+
+        int err = 0;
+        if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
+            // reset the native buffers and update the window
+            err = native_window_set_buffers_dimensions(mNativeWindow.get(),
+                                                       newWindowInfo.actualSize.width(),
+                                                       newWindowInfo.actualSize.height());
+            if (err != 0) {
+                ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
+                      newWindowInfo.actualSize.width(),
+                      newWindowInfo.actualSize.height(), strerror(-err), err);
+                return nullptr;
+            }
+            // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
+            // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
+            releaseBuffers();
+            // TODO should we ask the nativewindow to allocate buffers?
+        }
+
+        if (newWindowInfo.transform != mWindowInfo.transform) {
+            err = native_window_set_buffers_transform(mNativeWindow.get(),
+                    InvertTransform(newWindowInfo.transform));
+            if (err != 0) {
+                ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
+                      newWindowInfo.transform, strerror(-err), err);
+                newWindowInfo.transform = mWindowInfo.transform;
+                ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+            }
+        }
+
+        mWindowInfo = newWindowInfo;
+    }
+
+    ANativeWindowBuffer* buffer;
+    int fence_fd;
+    int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
+    if (err != 0) {
+        ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+        return nullptr;
+    }
+
+    uint32_t idx;
+    for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
+        if (mNativeBuffers[idx].buffer.get() == buffer) {
+            mNativeBuffers[idx].dequeued = true;
+            mNativeBuffers[idx].dequeue_fence = fence_fd;
+            break;
+        } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
+            // increasing the number of buffers we have allocated
+            mNativeBuffers[idx].buffer = buffer;
+            mNativeBuffers[idx].dequeued = true;
+            mNativeBuffers[idx].dequeue_fence = fence_fd;
+            break;
+        }
+    }
+    if (idx == mWindowInfo.bufferCount) {
+        ALOGE("dequeueBuffer returned unrecognized buffer");
+        mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+        return nullptr;
+    }
+
+    VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
+
+    if (bufferInfo->skSurface.get() == nullptr) {
+        bufferInfo->skSurface =
+                SkSurface::MakeFromAHardwareBuffer(mGrContext,
+                        ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
+                        kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace),
+                        nullptr);
+        if (bufferInfo->skSurface.get() == nullptr) {
+            ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
+            mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+            return nullptr;
+        }
+    }
+
+    mDequeuedIndex = idx;
+    return bufferInfo;
+}
+
+bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
+    if (!dirtyRect.isEmpty()) {
+        SkRect transformedRect;
+        mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect);
+
+        SkIRect transformedIRect;
+        transformedRect.roundOut(&transformedIRect);
+        transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight);
+
+        // map to bottom-left coordinate system
+        android_native_rect_t aRect;
+        aRect.left = transformedIRect.x();
+        aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height());
+        aRect.right = aRect.left + transformedIRect.width();
+        aRect.bottom = aRect.top - transformedIRect.height();
+
+        int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
+        ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
+    }
+
+    VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+    int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
+    int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
+
+    currentBuffer.dequeued = false;
+    // queueBuffer always closes fence, even on error
+    if (err != 0) {
+        ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
+        mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
+                                    currentBuffer.dequeue_fence);
+    } else {
+        currentBuffer.hasValidContents = true;
+        currentBuffer.lastPresentedCount = mPresentCount;
+        mPresentCount++;
+    }
+
+    if (currentBuffer.dequeue_fence >= 0) {
+        close(currentBuffer.dequeue_fence);
+        currentBuffer.dequeue_fence = -1;
+    }
+
+    return err == 0;
+}
+
+int VulkanSurface::getCurrentBuffersAge() {
+    VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+    return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
new file mode 100644
index 0000000..4fd9cd2
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <system/graphics.h>
+#include <system/window.h>
+#include <vulkan/vulkan.h>
+
+#include <SkSize.h>
+#include <SkRefCnt.h>
+
+#include "IRenderPipeline.h"
+
+class SkSurface;
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class VulkanManager;
+
+class VulkanSurface {
+public:
+    static VulkanSurface* Create(ANativeWindow* window,
+                                  ColorMode colorMode,
+                                  SkColorType colorType,
+                                  sk_sp<SkColorSpace> colorSpace,
+                                  GrContext* grContext,
+                                  const VulkanManager& vkManager);
+    ~VulkanSurface();
+
+    sk_sp<SkSurface> getCurrentSkSurface() { return mNativeBuffers[mDequeuedIndex].skSurface; }
+    const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
+
+private:
+    /*
+     * All structs/methods in this private section are specifically for use by the VulkanManager
+     *
+     */
+    friend VulkanManager;
+    struct NativeBufferInfo {
+        sk_sp<SkSurface> skSurface;
+        sp<ANativeWindowBuffer> buffer;
+        // The fence is only valid when the buffer is dequeued, and should be
+        // -1 any other time. When valid, we own the fd, and must ensure it is
+        // closed: either by closing it explicitly when queueing the buffer,
+        // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
+        int dequeue_fence = -1;
+        bool dequeued = false;
+        uint32_t lastPresentedCount = 0;
+        bool hasValidContents = false;
+    };
+
+    NativeBufferInfo* dequeueNativeBuffer();
+    NativeBufferInfo* getCurrentBufferInfo() { return &mNativeBuffers[mDequeuedIndex]; }
+    bool presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd);
+
+    // The width and height are are the logical width and height for when submitting draws to the
+    // surface. In reality if the window is rotated the underlying window may have the width and
+    // height swapped.
+    int logicalWidth() const { return mWindowInfo.size.width(); }
+    int logicalHeight() const { return mWindowInfo.size.height(); }
+    int getCurrentBuffersAge();
+
+private:
+    /*
+     * All code below this line while logically available to VulkanManager should not be treated
+     * as private to this class.
+     *
+     */
+    static constexpr int sMaxBufferCount = 3;
+
+    struct WindowInfo {
+        SkISize size;
+        PixelFormat pixelFormat;
+        android_dataspace dataspace;
+        int transform;
+        int bufferCount;
+        uint64_t windowUsageFlags;
+
+        // size of the ANativeWindow if the inverse of transform requires us to swap width/height
+        SkISize actualSize;
+        // transform to be applied to the SkSurface to map the coordinates to the provided transform
+        SkMatrix preTransform;
+    };
+
+    VulkanSurface(ANativeWindow* window,
+                  const WindowInfo& windowInfo,
+                  SkISize minWindowSize,
+                  SkISize maxWindowSize,
+                  GrContext* grContext);
+    static bool UpdateWindow(ANativeWindow* window,
+                             const WindowInfo& windowInfo);
+    static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo,
+                                              const SkISize& minSize,
+                                              const SkISize& maxSize);
+    void releaseBuffers();
+
+    NativeBufferInfo mNativeBuffers[VulkanSurface::sMaxBufferCount];
+
+    sp<ANativeWindow> mNativeWindow;
+    WindowInfo mWindowInfo;
+    GrContext* mGrContext;
+
+    int mDequeuedIndex = -1;
+    uint32_t mPresentCount = 0;
+
+    const SkISize mMinWindowSize;
+    const SkISize mMaxWindowSize;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index ba361c4..46288bb 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -22,7 +22,6 @@
 import android.os.Handler;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -128,17 +127,17 @@
     }
 
     private void updateFromDeviceConfigFlags() {
-        mGenerateReplies = DeviceConfigHelper.getBoolean(
+        mGenerateReplies = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
 
-        mGenerateActions = DeviceConfigHelper.getBoolean(
+        mGenerateActions = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
 
-        mMaxMessagesToExtract = DeviceConfigHelper.getInteger(
+        mMaxMessagesToExtract = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
                 DEFAULT_MAX_MESSAGES_TO_EXTRACT);
 
-        mMaxSuggestions = DeviceConfigHelper.getInteger(
+        mMaxSuggestions = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS);
 
         mOnUpdateRunnable.run();
@@ -170,34 +169,6 @@
         mOnUpdateRunnable.run();
     }
 
-    static class DeviceConfigHelper {
-
-        static int getInteger(String key, int defaultValue) {
-            String value = getValue(key);
-            if (TextUtils.isEmpty(value)) {
-                return defaultValue;
-            }
-            try {
-                return Integer.parseInt(value);
-            } catch (NumberFormatException ex) {
-                return defaultValue;
-            }
-        }
-
-        static boolean getBoolean(String key, boolean defaultValue) {
-            String value = getValue(key);
-            if (TextUtils.isEmpty(value)) {
-                return defaultValue;
-            }
-            return Boolean.parseBoolean(value);
-        }
-
-        private static String getValue(String key) {
-            return DeviceConfig.getProperty(
-                    DeviceConfig.NAMESPACE_SYSTEMUI, key);
-        }
-    }
-
     public interface Factory {
         AssistantSettings createAndRegister(Handler handler, ContentResolver resolver, int userId,
                 Runnable onUpdateRunnable);
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index 293b5b8..ad52e2b 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -120,7 +120,7 @@
     }
 
     @Test
-    public void testGenerateRepliesEmptyFlag() {
+    public void testGenerateRepliesNullFlag() {
         runWithShellPermissionIdentity(() -> setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
@@ -136,12 +136,12 @@
         runWithShellPermissionIdentity(() -> setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                "",
+                null,
                 false /* makeDefault */));
         mAssistantSettings.onDeviceConfigPropertyChanged(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
-                "");
+                null);
 
         // Go back to the default value.
         assertTrue(mAssistantSettings.mGenerateReplies);
@@ -178,7 +178,7 @@
     }
 
     @Test
-    public void testGenerateActionsEmptyFlag() {
+    public void testGenerateActionsNullFlag() {
         runWithShellPermissionIdentity(() -> setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
@@ -194,12 +194,12 @@
         runWithShellPermissionIdentity(() -> setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                "",
+                null,
                 false /* makeDefault */));
         mAssistantSettings.onDeviceConfigPropertyChanged(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
-                "");
+                null);
 
         // Go back to the default value.
         assertTrue(mAssistantSettings.mGenerateActions);
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index f210840..190247a 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -14,12 +14,11 @@
 // limitations under the License.
 //
 
-// Library including the network stack, used to compile the network stack app, or linked into the
-// system server on devices that run the stack there
-java_library {
-    name: "NetworkStackLib",
+// Library including the network stack, used to compile both variants of the network stack
+android_library {
+    name: "NetworkStackBase",
     sdk_version: "system_current",
-    installable: true,
+    min_sdk_version: "28",
     srcs: [
         "src/**/*.java",
         ":framework-networkstack-shared-srcs",
@@ -29,7 +28,24 @@
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
         "datastallprotosnano",
-    ]
+    ],
+    manifest: "AndroidManifestBase.xml",
+}
+
+// Non-updatable in-process network stack for devices not using the module
+android_app {
+    name: "InProcessNetworkStack",
+    sdk_version: "system_current",
+    min_sdk_version: "28",
+    certificate: "platform",
+    privileged: true,
+    static_libs: [
+        "NetworkStackBase",
+    ],
+    jarjar_rules: "jarjar-rules-shared.txt",
+    // The permission configuration *must* be included to ensure security of the device
+    required: ["NetworkStackPermissionStub"],
+    manifest: "AndroidManifest_InProcess.xml",
 }
 
 // Updatable network stack packaged as an application
@@ -40,9 +56,10 @@
     certificate: "networkstack",
     privileged: true,
     static_libs: [
-        "NetworkStackLib"
+        "NetworkStackBase"
     ],
     jarjar_rules: "jarjar-rules-shared.txt",
-    manifest: "AndroidManifest.xml",
+    // The permission configuration *must* be included to ensure security of the device
     required: ["NetworkStackPermissionStub"],
+    manifest: "AndroidManifest.xml",
 }
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 003f1e5..a90db11 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,30 +18,14 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack"
-          android:sharedUserId="android.uid.networkstack"
-          android:versionCode="11"
-          android:versionName="Q-initial">
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+          android:sharedUserId="android.uid.networkstack">
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
-    <!-- Send latency broadcast as current user -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
-    <application
-        android:label="NetworkStack"
-        android:defaultToDeviceProtectedStorage="true"
-        android:directBootAware="true"
-        android:usesCleartextTraffic="true">
+    <application>
         <service android:name="com.android.server.NetworkStackService">
             <intent-filter>
                 <action android:name="android.net.INetworkStackConnector"/>
             </intent-filter>
         </service>
     </application>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
new file mode 100644
index 0000000..621d30c
--- /dev/null
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.networkstack"
+          android:versionCode="11"
+          android:versionName="Q-initial">
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <!-- Send latency broadcast as current user -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    <application
+        android:label="NetworkStack"
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true"
+        android:usesCleartextTraffic="true">
+    </application>
+</manifest>
diff --git a/packages/NetworkStack/AndroidManifest_InProcess.xml b/packages/NetworkStack/AndroidManifest_InProcess.xml
new file mode 100644
index 0000000..48fcecd
--- /dev/null
+++ b/packages/NetworkStack/AndroidManifest_InProcess.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.networkstack.inprocess"
+          android:sharedUserId="android.uid.system"
+          android:process="system">
+    <application>
+        <service android:name="com.android.server.NetworkStackService" android:process="system">
+            <intent-filter>
+                <action android:name="android.net.INetworkStackConnector.InProcess"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index e64f284..aadf99e 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -23,7 +23,7 @@
     static_libs: [
         "androidx.test.rules",
         "mockito-target-extended-minus-junit4",
-        "NetworkStackLib",
+        "NetworkStackBase",
         "testables",
     ],
     libs: [
diff --git a/packages/SettingsLib/res/drawable/ic_smartphone.xml b/packages/SettingsLib/res/drawable/ic_smartphone.xml
new file mode 100644
index 0000000..84a96da
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_smartphone.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="24dp"
+        android:height="24dp"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0 0h24v24H0z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M17 1.01L7 1c-1.1 0-2 0.9-2 2v18c0 1.1 0.9 2 2 2h10c1.1 0 2 -0.9 2-2V3c0-1.1 -0.9-1.99-2-1.99zM17 19H7V5h10v14z" />
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c60e8c3..bf97d77 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -937,7 +937,7 @@
     <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time_remaining">%1$s</xliff:g> left based on your usage</string>
     <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
     <string name="power_discharging_duration_enhanced">About <xliff:g id="time_remaining">%1$s</xliff:g> left based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
-    <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+    <!-- [CHAR_LIMIT=20] Short label for estimated remaining duration of battery charging/discharging -->
     <string name="power_remaining_duration_only_short"><xliff:g id="time_remaining">%1$s</xliff:g></string>
 
     <!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery -->
@@ -948,7 +948,7 @@
     <string name="power_discharge_by">Should last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
     <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
     <string name="power_discharge_by_only">Should last until about <xliff:g id="time">%1$s</xliff:g></string>
-    <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
+    <!-- [CHAR_LIMIT=20] Label for estimated time that phone will run out of battery -->
     <string name="power_discharge_by_only_short">Until <xliff:g id="time" example="12 PM">%1$s</xliff:g></string>
     <!-- [CHAR_LIMIT=100] Extend the battery life past a certain time -->
     <string name="power_suggestion_extend_battery">Extend battery life past <xliff:g id="time" example="12 PM">%1$s</xliff:g></string>
@@ -1153,6 +1153,6 @@
     <!-- The notice header of Third-party licenses. not translatable -->
     <string name="notice_header" translatable="false"></string>
 
-    <!-- Name of the phone device [CHAR LIMIT=NONE] -->
-    <string name="media_transfer_phone_device_name">Phone speaker</string>
+    <!-- Name of the this device. [CHAR LIMIT=30] -->
+    <string name="media_transfer_this_device_name">This device</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 6d0e3ac..3092b99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -16,6 +16,7 @@
 package com.android.settingslib.media;
 
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.util.Log;
 
@@ -42,6 +43,11 @@
     }
 
     @Override
+    public String getSummary() {
+        return mCachedDevice.getConnectionSummary();
+    }
+
+    @Override
     public int getIcon() {
         //TODO(b/117129183): This is not final icon for bluetooth device, just for demo.
         return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
@@ -86,4 +92,10 @@
         }
         return false;
     }
+
+    @Override
+    public boolean isConnected() {
+        return mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+                && mCachedDevice.isConnected();
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index fa2dd88..3a738d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -41,6 +41,9 @@
 
     private static final String TAG = "BluetoothMediaManager";
 
+    private final DeviceAttributeChangeCallback mDeviceAttributeChangeCallback =
+            new DeviceAttributeChangeCallback();
+
     private LocalBluetoothManager mLocalBluetoothManager;
     private LocalBluetoothProfileManager mProfileManager;
     private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
@@ -65,7 +68,10 @@
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         buildBluetoothDeviceList();
         dispatchDeviceListAdded();
+        addServiceListenerIfNecessary();
+    }
 
+    private void addServiceListenerIfNecessary() {
         // The profile may not ready when calling startScan().
         // Device status are all disconnected since profiles are not ready to connected.
         // In this case, we observe onServiceConnected() in LocalBluetoothProfileManager.
@@ -78,18 +84,18 @@
 
     private void buildBluetoothDeviceList() {
         mMediaDevices.clear();
-        addConnectedA2dpDevices();
-        addConnectedHearingAidDevices();
+        addConnectableA2dpDevices();
+        addConnectableHearingAidDevices();
     }
 
-    private void addConnectedA2dpDevices() {
+    private void addConnectableA2dpDevices() {
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile == null) {
-            Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!");
+            Log.w(TAG, "addConnectableA2dpDevices() a2dp profile is null!");
             return;
         }
 
-        final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
+        final List<BluetoothDevice> devices = a2dpProfile.getConnectableDevices();
 
         for (BluetoothDevice device : devices) {
             final CachedBluetoothDevice cachedDevice =
@@ -100,10 +106,12 @@
                 continue;
             }
 
-            Log.d(TAG, "addConnectedA2dpDevices() device : " + cachedDevice.getName()
-                    + ", is connected : " + cachedDevice.isConnected());
+            Log.d(TAG, "addConnectableA2dpDevices() device : " + cachedDevice.getName()
+                    + ", is connected : " + cachedDevice.isConnected()
+                    + ", is preferred : " + a2dpProfile.isPreferred(device));
 
-            if (cachedDevice.isConnected()) {
+            if (a2dpProfile.isPreferred(device)
+                    && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
                 addMediaDevice(cachedDevice);
             }
         }
@@ -111,15 +119,15 @@
         mIsA2dpProfileReady = a2dpProfile.isProfileReady();
     }
 
-    private void addConnectedHearingAidDevices() {
+    private void addConnectableHearingAidDevices() {
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         if (hapProfile == null) {
-            Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!");
+            Log.w(TAG, "addConnectableHearingAidDevices() hap profile is null!");
             return;
         }
 
         final List<Long> devicesHiSyncIds = new ArrayList<>();
-        final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
+        final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
 
         for (BluetoothDevice device : devices) {
             final CachedBluetoothDevice cachedDevice =
@@ -130,13 +138,16 @@
                 continue;
             }
 
-            Log.d(TAG, "addConnectedHearingAidDevices() device : " + cachedDevice.getName()
-                    + ", is connected : " + cachedDevice.isConnected());
+            Log.d(TAG, "addConnectableHearingAidDevices() device : " + cachedDevice.getName()
+                    + ", is connected : " + cachedDevice.isConnected()
+                    + ", is preferred : " + hapProfile.isPreferred(device));
+
             final long hiSyncId = hapProfile.getHiSyncId(device);
 
             // device with same hiSyncId should not be shown in the UI.
             // So do not add it into connectedDevices.
-            if (!devicesHiSyncIds.contains(hiSyncId) && cachedDevice.isConnected()) {
+            if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isPreferred(device)
+                    && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
                 devicesHiSyncIds.add(hiSyncId);
                 addMediaDevice(cachedDevice);
             }
@@ -149,6 +160,7 @@
         MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice == null) {
             mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice);
+            cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
             mLastAddedDevice = mediaDevice;
             mMediaDevices.add(mediaDevice);
         }
@@ -157,6 +169,14 @@
     @Override
     public void stopScan() {
         mLocalBluetoothManager.getEventManager().unregisterCallback(this);
+        unregisterDeviceAttributeChangeCallback();
+    }
+
+    private void unregisterDeviceAttributeChangeCallback() {
+        for (MediaDevice device : mMediaDevices) {
+            ((BluetoothMediaDevice) device).getCachedDevice()
+                    .unregisterCallback(mDeviceAttributeChangeCallback);
+        }
     }
 
     @Override
@@ -164,12 +184,13 @@
         if (BluetoothAdapter.STATE_ON == bluetoothState) {
             buildBluetoothDeviceList();
             dispatchDeviceListAdded();
+            addServiceListenerIfNecessary();
         } else if (BluetoothAdapter.STATE_OFF == bluetoothState) {
             final List<MediaDevice> removeDevicesList = new ArrayList<>();
             for (MediaDevice device : mMediaDevices) {
-                if (device instanceof BluetoothMediaDevice) {
-                    removeDevicesList.add(device);
-                }
+                ((BluetoothMediaDevice) device).getCachedDevice()
+                        .unregisterCallback(mDeviceAttributeChangeCallback);
+                removeDevicesList.add(device);
             }
             mMediaDevices.removeAll(removeDevicesList);
             dispatchDeviceListRemoved(removeDevicesList);
@@ -212,6 +233,7 @@
     private void removeMediaDevice(CachedBluetoothDevice cachedDevice) {
         final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice != null) {
+            cachedDevice.unregisterCallback(mDeviceAttributeChangeCallback);
             mLastRemovedDevice = mediaDevice;
             mMediaDevices.remove(mediaDevice);
         }
@@ -230,12 +252,17 @@
         Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice
                 + ", state: " + state + ", bluetoothProfile: " + bluetoothProfile);
 
-        if (isCachedDeviceConnected(cachedDevice)) {
-            addMediaDevice(cachedDevice);
-            dispatchDeviceAdded(cachedDevice);
-        } else {
+        updateMediaDeviceListIfNecessary(cachedDevice);
+    }
+
+    private void updateMediaDeviceListIfNecessary(CachedBluetoothDevice cachedDevice) {
+        if (BluetoothDevice.BOND_NONE == cachedDevice.getBondState()) {
             removeMediaDevice(cachedDevice);
             dispatchDeviceRemoved(cachedDevice);
+        } else {
+            if (findMediaDevice(MediaDeviceUtils.getId(cachedDevice)) != null) {
+                dispatchDataChanged();
+            }
         }
     }
 
@@ -243,13 +270,7 @@
     public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
         Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice + ", state: " + state);
 
-        if (isCachedDeviceConnected(cachedDevice)) {
-            addMediaDevice(cachedDevice);
-            dispatchDeviceAdded(cachedDevice);
-        } else {
-            removeMediaDevice(cachedDevice);
-            dispatchDeviceRemoved(cachedDevice);
-        }
+        updateMediaDeviceListIfNecessary(cachedDevice);
     }
 
     @Override
@@ -281,4 +302,16 @@
     public void onServiceDisconnected() {
 
     }
+
+    /**
+     * This callback is for update {@link BluetoothMediaDevice} summary when
+     * {@link CachedBluetoothDevice} connection state is changed.
+     */
+    private class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
+
+        @Override
+        public void onDeviceAttributesChanged() {
+            dispatchDataChanged();
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 99d9d1c..95f3d3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -41,6 +41,11 @@
     }
 
     @Override
+    public String getSummary() {
+        return null;
+    }
+
+    @Override
     public int getIcon() {
         //TODO(b/121083246): This is not final icon for cast device, just for demo.
         return com.android.internal.R.drawable.ic_settings_print;
@@ -63,4 +68,9 @@
     public void disconnect() {
         //TODO(b/121083246): disconnected last select device
     }
+
+    @Override
+    public boolean isConnected() {
+        return true;
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 44d945a..4e16c66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -58,7 +58,6 @@
 
     private Context mContext;
     private BluetoothMediaManager mBluetoothMediaManager;
-    private InfoMediaManager mInfoMediaManager;
     private LocalBluetoothManager mLocalBluetoothManager;
 
     @VisibleForTesting
@@ -97,7 +96,6 @@
 
         mBluetoothMediaManager =
                 new BluetoothMediaManager(context, mLocalBluetoothManager, notification);
-        mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
     }
 
     @VisibleForTesting
@@ -106,7 +104,6 @@
         mContext = context;
         mLocalBluetoothManager = localBluetoothManager;
         mBluetoothMediaManager = bluetoothMediaManager;
-        mInfoMediaManager = infoMediaManager;
     }
 
     /**
@@ -115,6 +112,15 @@
      */
     public void connectDevice(MediaDevice connectDevice) {
         final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
+        if (device instanceof BluetoothMediaDevice) {
+            final CachedBluetoothDevice cachedDevice =
+                    ((BluetoothMediaDevice) device).getCachedDevice();
+            if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
+                cachedDevice.connect(true);
+                return;
+            }
+        }
+
         if (device == mCurrentConnectedDevice) {
             Log.d(TAG, "connectDevice() this device all ready connected! : " + device.getName());
             return;
@@ -150,9 +156,7 @@
     public void startScan() {
         mMediaDevices.clear();
         mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
-        mInfoMediaManager.registerCallback(mMediaDeviceCallback);
         mBluetoothMediaManager.startScan();
-        mInfoMediaManager.startScan();
     }
 
     private void addPhoneDeviceIfNecessary() {
@@ -186,9 +190,7 @@
      */
     public void stopScan() {
         mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
-        mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
         mBluetoothMediaManager.stopScan();
-        mInfoMediaManager.stopScan();
     }
 
     /**
@@ -252,9 +254,17 @@
             }
             addPhoneDeviceIfNecessary();
             mCurrentConnectedDevice = updateCurrentConnectedDevice();
+            updatePhoneMediaDeviceSummary();
             dispatchDeviceListUpdate();
         }
 
+        private void updatePhoneMediaDeviceSummary() {
+            if (mPhoneDevice != null) {
+                ((PhoneMediaDevice) mPhoneDevice)
+                        .updateSummary(mCurrentConnectedDevice == mPhoneDevice);
+            }
+        }
+
         @Override
         public void onDeviceRemoved(MediaDevice device) {
             if (mMediaDevices.contains(device)) {
@@ -272,21 +282,22 @@
         }
 
         @Override
-        public void onDeviceAttributesChanged() {
-            dispatchDeviceListUpdate();
-        }
-
-        @Override
         public void onConnectedDeviceChanged(String id) {
             final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
 
             if (connectDevice == mCurrentConnectedDevice) {
-                Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected! : "
-                        + connectDevice.getName());
+                Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
                 return;
             }
             mCurrentConnectedDevice = connectDevice;
+            updatePhoneMediaDeviceSummary();
+            dispatchDeviceListUpdate();
+        }
 
+        @Override
+        public void onDeviceAttributesChanged() {
+            addPhoneDeviceIfNecessary();
+            removePhoneMediaDeviceIfNecessary();
             dispatchDeviceListUpdate();
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index f35c30e..9b9e803 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -34,9 +34,9 @@
             MediaDeviceType.TYPE_BLUETOOTH_DEVICE,
             MediaDeviceType.TYPE_PHONE_DEVICE})
     public @interface MediaDeviceType {
-        int TYPE_CAST_DEVICE = 1;
-        int TYPE_BLUETOOTH_DEVICE = 2;
-        int TYPE_PHONE_DEVICE = 3;
+        int TYPE_PHONE_DEVICE = 1;
+        int TYPE_CAST_DEVICE = 2;
+        int TYPE_BLUETOOTH_DEVICE = 3;
     }
 
     private int mConnectedRecord;
@@ -63,6 +63,13 @@
     public abstract String getName();
 
     /**
+     * Get summary from MediaDevice.
+     *
+     * @return summary of MediaDevice.
+     */
+    public abstract String getSummary();
+
+    /**
      * Get resource id of MediaDevice.
      *
      * @return resource id of MediaDevice.
@@ -94,6 +101,13 @@
     public abstract void disconnect();
 
     /**
+     * According the MediaDevice type to check whether we are connected to this MediaDevice.
+     *
+     * @return Whether it is connected.
+     */
+    public abstract boolean isConnected();
+
+    /**
      * Rules:
      * 1. If there is one of the connected devices identified as a carkit, this carkit will
      * be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule.
@@ -103,9 +117,11 @@
      * 3. For devices with usage record.
      * The most recent used one + device group with usage info sorted by how many times the
      * device has been used.
+     * 4. Phone device always in the top and the connected Bluetooth devices, cast devices and
+     * phone device will be always above on the disconnect Bluetooth devices.
      *
-     * So the device list will look like 4 slots ranked as below.
-     * Rule 1 + the most recently used device + Rule 3 + Rule 2
+     * So the device list will look like 5 slots ranked as below.
+     * Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2
      * Any slot could be empty. And available device will belong to one of the slots.
      *
      * @return a negative integer, zero, or a positive integer
@@ -113,6 +129,21 @@
      */
     @Override
     public int compareTo(MediaDevice another) {
+        // Check Bluetooth device is have same connection state
+        if (isConnected() ^ another.isConnected()) {
+            if (isConnected()) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+
+        // Phone device always in the top.
+        if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
+            return -1;
+        } else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
+            return 1;
+        }
         // Check carkit
         if (isCarKitDevice()) {
             return -1;
@@ -138,7 +169,7 @@
             final String s2 = another.getName();
             return s1.compareToIgnoreCase(s2);
         }
-        // Both devices have never been used, the priority is Cast > Bluetooth > Phone
+        // Both devices have never been used, the priority is Phone > Cast > Bluetooth
         return mType - another.mType;
     }
 
@@ -149,4 +180,13 @@
     protected boolean isCarKitDevice() {
         return false;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof MediaDevice)) {
+            return false;
+        }
+        final MediaDevice otherDevice = (MediaDevice) obj;
+        return otherDevice.getId().equals(getId());
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index 2c3a96c..7898982 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -117,6 +117,14 @@
         }
     }
 
+    protected void dispatchDataChanged() {
+        synchronized (mCallbacks) {
+            for (MediaDeviceCallback callback : mCallbacks) {
+                callback.onDeviceAttributesChanged();
+            }
+        }
+    }
+
     /**
      * Callback for notifying device is added, removed and attributes changed.
      */
@@ -150,15 +158,16 @@
         void onDeviceListRemoved(List<MediaDevice> devices);
 
         /**
-         * Callback for notifying MediaDevice attributes is changed.
-         */
-        void onDeviceAttributesChanged();
-
-        /**
          * Callback for notifying connected MediaDevice is changed.
          *
          * @param id the id of MediaDevice
          */
         void onConnectedDeviceChanged(String id);
+
+        /**
+         * Callback for notifying that MediaDevice attributes
+         * (e.g: device name, connection state, subtitle) is changed.
+         */
+        void onDeviceAttributesChanged();
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 8ec2a7f..da140aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.util.Log;
 
+import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -34,6 +35,7 @@
 
     private LocalBluetoothProfileManager mProfileManager;
     private LocalBluetoothManager mLocalBluetoothManager;
+    private String mSummary = "";
 
     PhoneMediaDevice(Context context, LocalBluetoothManager localBluetoothManager) {
         super(context, MediaDeviceType.TYPE_PHONE_DEVICE);
@@ -45,14 +47,17 @@
 
     @Override
     public String getName() {
-        return mContext
-                .getString(com.android.settingslib.R.string.media_transfer_phone_device_name);
+        return mContext.getString(R.string.media_transfer_this_device_name);
+    }
+
+    @Override
+    public String getSummary() {
+        return mSummary;
     }
 
     @Override
     public int getIcon() {
-        //TODO(b/117129183): This is not final icon for phone device, just for demo.
-        return com.android.internal.R.drawable.ic_phone;
+        return R.drawable.ic_smartphone;
     }
 
     @Override
@@ -69,6 +74,7 @@
 
         if (hapProfile != null && a2dpProfile != null) {
             isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
+            updateSummary(true);
             setConnectedRecord();
         }
         Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
@@ -77,6 +83,20 @@
 
     @Override
     public void disconnect() {
-        //TODO(b/117129183): disconnected last select device
+        updateSummary(false);
+    }
+
+    @Override
+    public boolean isConnected() {
+        return true;
+    }
+
+    /**
+     * According current active device is {@link PhoneMediaDevice} or not to update summary.
+     */
+    public void updateSummary(boolean isActive) {
+        mSummary = isActive
+                ? mContext.getString(R.string.bluetooth_active_no_battery_level)
+                : "";
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
index 5600dd2..7046d23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -223,12 +223,19 @@
     }
 
     private static String getRegularTimeRemainingShortString(Context context, long drainTimeMs) {
-        // Get the time remaining rounded to the nearest 15 min
-        final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, FIFTEEN_MINUTES_MILLIS);
-        CharSequence timeString = StringUtil.formatElapsedTime(context, roundedTimeMs,
-                false /* withSeconds */);
+        // Get the time of day we think device will die rounded to the nearest 15 min.
+        final long roundedTimeOfDayMs =
+                roundTimeToNearestThreshold(
+                        System.currentTimeMillis() + drainTimeMs,
+                        FIFTEEN_MINUTES_MILLIS);
 
-        return context.getString(R.string.power_remaining_duration_only_short, timeString);
+        // convert the time to a properly formatted string.
+        String skeleton = android.text.format.DateFormat.getTimeFormatString(context);
+        DateFormat fmt = DateFormat.getInstanceForSkeleton(skeleton);
+        Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs));
+        CharSequence timeString = fmt.format(date);
+
+        return context.getString(R.string.power_discharge_by_only_short, timeString);
     }
 
     public static long convertUsToMs(long timeUs) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index d9b4885..59fbb72 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1076,7 +1076,7 @@
             return (info.isOsuAp() && mOsuStatus != null);
         } else if (info.isPasspointAp() || isPasspoint()) {
             return (info.isPasspointAp() && isPasspoint()
-                    && TextUtils.equals(info.getFqdn(), mConfig.FQDN));
+                    && TextUtils.equals(info.getPasspointFqdn(), mConfig.FQDN));
         }
 
         if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 3c10688..2ab369c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -118,7 +118,7 @@
                 mWifiInfo = mWifiManager.getConnectionInfo();
                 if (mWifiInfo != null) {
                     if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
-                        ssid = mWifiInfo.getProviderFriendlyName();
+                        ssid = mWifiInfo.getPasspointProviderFriendlyName();
                     } else {
                         ssid = getValidSsid(mWifiInfo);
                     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
index e5d1b18..e0e2fd6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 
@@ -66,4 +67,20 @@
 
         assertThat(mBluetoothMediaDevice.connect()).isFalse();
     }
+
+    @Test
+    public void isCachedBluetoothDeviceConnected_deviceConnected_returnTrue() {
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice.isConnected()).thenReturn(true);
+
+        assertThat(mBluetoothMediaDevice.isConnected()).isTrue();
+    }
+
+    @Test
+    public void isCachedBluetoothDeviceConnected_deviceNotConnected_returnFalse() {
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice.isConnected()).thenReturn(false);
+
+        assertThat(mBluetoothMediaDevice.isConnected()).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
index a20e22b..48449f2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -87,15 +87,16 @@
     }
 
     @Test
-    public void startScan_haveA2dpProfileConnectedBluetoothDevice_shouldAddDevice() {
+    public void startScan_haveA2dpProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
         final List<BluetoothDevice> devices = new ArrayList<>();
         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
         final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
         devices.add(bluetoothDevice);
 
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
-        when(cachedDevice.isConnected()).thenReturn(true);
+        when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -103,15 +104,16 @@
     }
 
     @Test
-    public void startScan_haveA2dpProfileDisconnectedBluetoothDevice_shouldNotAddDevice() {
+    public void startScan_haveA2dpProfileDeviceIsPreferredAndBondNone_shouldNotAddDevice() {
         final List<BluetoothDevice> devices = new ArrayList<>();
         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
         final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
         devices.add(bluetoothDevice);
 
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
-        when(cachedDevice.isConnected()).thenReturn(false);
+        when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+        when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -122,7 +124,7 @@
     public void startScan_noA2dpProfileBluetoothDevice_shouldNotAddDevice() {
         final List<BluetoothDevice> devices = new ArrayList<>();
 
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -130,15 +132,16 @@
     }
 
     @Test
-    public void startScan_haveHapProfileConnectedBluetoothDevice_shouldAddDevice() {
+    public void startScan_haveHapProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
         final List<BluetoothDevice> devices = new ArrayList<>();
         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
         final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
         devices.add(bluetoothDevice);
 
-        when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+        when(mHapProfile.getConnectableDevices()).thenReturn(devices);
         when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
-        when(cachedDevice.isConnected()).thenReturn(true);
+        when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mHapProfile.isPreferred(bluetoothDevice)).thenReturn(true);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -149,7 +152,7 @@
     public void startScan_noHapProfileBluetoothDevice_shouldNotAddDevice() {
         final List<BluetoothDevice> devices = new ArrayList<>();
 
-        when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+        when(mHapProfile.getConnectableDevices()).thenReturn(devices);
 
         assertThat(mMediaManager.mMediaDevices).isEmpty();
         mMediaManager.startScan();
@@ -230,9 +233,14 @@
     public void onBluetoothStateChanged_bluetoothStateIsOff_callOnDeviceListRemoved() {
         final BluetoothMediaDevice device1 = mock(BluetoothMediaDevice.class);
         final BluetoothMediaDevice device2 = mock(BluetoothMediaDevice.class);
+        final CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+        final CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
         mMediaManager.mMediaDevices.add(device1);
         mMediaManager.mMediaDevices.add(device2);
 
+        when(device1.getCachedDevice()).thenReturn(cachedDevice1);
+        when(device2.getCachedDevice()).thenReturn(cachedDevice2);
+
         mMediaManager.registerCallback(mCallback);
         mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
 
@@ -311,28 +319,30 @@
     }
 
     @Test
-    public void onProfileConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
-        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-
-        when(device.isConnectedHearingAidDevice()).thenReturn(true);
-        when(device.isConnectedA2dpDevice()).thenReturn(true);
-
-        assertThat(mMediaManager.mMediaDevices).isEmpty();
-        mMediaManager.registerCallback(mCallback);
-        mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
-
-        assertThat(mMediaManager.mMediaDevices).hasSize(1);
-        verify(mCallback).onDeviceAdded(any());
-    }
-
-    @Test
-    public void onProfileConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+    public void onProfileConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
         final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
         final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
         mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
 
-        when(device.isConnectedHearingAidDevice()).thenReturn(false);
-        when(device.isConnectedA2dpDevice()).thenReturn(false);
+        when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback).onDeviceAttributesChanged();
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
         when(device.getAddress()).thenReturn(TEST_ADDRESS);
         when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
 
@@ -345,28 +355,30 @@
     }
 
     @Test
-    public void onAclConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
-        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-
-        when(device.isConnectedHearingAidDevice()).thenReturn(true);
-        when(device.isConnectedA2dpDevice()).thenReturn(true);
-
-        assertThat(mMediaManager.mMediaDevices).isEmpty();
-        mMediaManager.registerCallback(mCallback);
-        mMediaManager.onAclConnectionStateChanged(device, 0);
-
-        assertThat(mMediaManager.mMediaDevices).hasSize(1);
-        verify(mCallback).onDeviceAdded(any());
-    }
-
-    @Test
-    public void onAclConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+    public void onAclConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
         final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
         final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
         mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
 
-        when(device.isConnectedHearingAidDevice()).thenReturn(false);
-        when(device.isConnectedA2dpDevice()).thenReturn(false);
+        when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onAclConnectionStateChanged(device, 0);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback).onDeviceAttributesChanged();
+    }
+
+    @Test
+    public void onAclConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
         when(device.getAddress()).thenReturn(TEST_ADDRESS);
         when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 3556814..98bb74a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 
 import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -113,6 +114,23 @@
     }
 
     @Test
+    public void connectDevice_bluetoothDeviceNotConnected_connectBluetoothDevice() {
+        final MediaDevice device = mock(BluetoothMediaDevice.class);
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device);
+
+        when(device.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice);
+        when(cachedDevice.isConnected()).thenReturn(false);
+        when(cachedDevice.isBusy()).thenReturn(false);
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.connectDevice(device);
+
+        verify(cachedDevice).connect(true);
+    }
+
+    @Test
     public void getMediaDeviceById_idExist_shouldReturnMediaDevice() {
         final MediaDevice device1 = mock(MediaDevice.class);
         final MediaDevice device2 = mock(MediaDevice.class);
@@ -322,15 +340,6 @@
     }
 
     @Test
-    public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
-        mLocalMediaManager.registerCallback(mCallback);
-
-        mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
-
-        verify(mCallback).onDeviceListUpdate(any());
-    }
-
-    @Test
     public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreDifferent_notifyThemChanged() {
         final MediaDevice device1 = mock(MediaDevice.class);
         final MediaDevice device2 = mock(MediaDevice.class);
@@ -366,4 +375,13 @@
 
         verify(mCallback, never()).onDeviceListUpdate(any());
     }
+
+    @Test
+    public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
+        mLocalMediaManager.registerCallback(mCallback);
+
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
+
+        verify(mCallback).onDeviceListUpdate(any());
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index fc514f0..23d2c74 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -114,6 +114,12 @@
         when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
         when(mCachedDevice2.getDevice()).thenReturn(mDevice2);
         when(mCachedDevice3.getDevice()).thenReturn(mDevice3);
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.isConnected()).thenReturn(true);
+        when(mCachedDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice2.isConnected()).thenReturn(true);
+        when(mCachedDevice3.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice3.isConnected()).thenReturn(true);
         when(mRouteInfo1.getId()).thenReturn(ROUTER_ID_1);
         when(mRouteInfo2.getId()).thenReturn(ROUTER_ID_2);
         when(mRouteInfo3.getId()).thenReturn(ROUTER_ID_3);
@@ -158,12 +164,25 @@
     }
 
     @Test
-    public void compareTo_carKit_phone_carKitFirst() {
+    public void compareTo_carKit_phone_phoneFirst() {
         when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
-        mMediaDevices.add(mPhoneMediaDevice);
         mMediaDevices.add(mBluetoothMediaDevice1);
+        mMediaDevices.add(mPhoneMediaDevice);
 
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+        Collections.sort(mMediaDevices, COMPARATOR);
         assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
+    }
+
+    @Test
+    public void compareTo_carKitIsDisConnected_nonCarKitBluetooth_nonCarKitBluetoothFirst() {
+        when(mDevice1.getBluetoothClass()).thenReturn(mHeadreeClass);
+        when(mDevice2.getBluetoothClass()).thenReturn(mCarkitClass);
+        when(mCachedDevice2.isConnected()).thenReturn(false);
+        mMediaDevices.add(mBluetoothMediaDevice1);
+        mMediaDevices.add(mBluetoothMediaDevice2);
+
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
         Collections.sort(mMediaDevices, COMPARATOR);
         assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
     }
@@ -178,6 +197,7 @@
         Collections.sort(mMediaDevices, COMPARATOR);
         assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
     }
+
     @Test
     public void compareTo_connectionRecord_sortByRecord() {
         mMediaDevices.add(mBluetoothMediaDevice1);
@@ -196,6 +216,25 @@
     }
 
     @Test
+    public void compareTo_sortByRecord_connectedDeviceFirst() {
+        mMediaDevices.add(mBluetoothMediaDevice1);
+        mMediaDevices.add(mBluetoothMediaDevice2);
+        when(mCachedDevice2.isConnected()).thenReturn(false);
+
+        mBluetoothMediaDevice1.connect();
+        mBluetoothMediaDevice2.connect();
+        mBluetoothMediaDevice2.connect();
+        // Reset last selected record
+        ConnectionRecordManager.getInstance().setConnectionRecord(mContext, null, 0);
+
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+        assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
+        Collections.sort(mMediaDevices, COMPARATOR);
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+        assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
+    }
+
+    @Test
     public void compareTo_info_bluetooth_infoFirst() {
         mMediaDevices.add(mBluetoothMediaDevice1);
         mMediaDevices.add(mInfoMediaDevice1);
@@ -206,13 +245,13 @@
     }
 
     @Test
-    public void compareTo_bluetooth_phone_bluetoothFirst() {
-        mMediaDevices.add(mPhoneMediaDevice);
+    public void compareTo_bluetooth_phone_phoneFirst() {
         mMediaDevices.add(mBluetoothMediaDevice1);
+        mMediaDevices.add(mPhoneMediaDevice);
 
-        assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
-        Collections.sort(mMediaDevices, COMPARATOR);
         assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+        Collections.sort(mMediaDevices, COMPARATOR);
+        assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
     }
 
     @Test
@@ -235,6 +274,17 @@
         assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
     }
 
+    @Test
+    public void compareTo_sortByAlphabet_connectDeviceFirst() {
+        mMediaDevices.add(mBluetoothMediaDevice2);
+        mMediaDevices.add(mBluetoothMediaDevice1);
+        when(mCachedDevice1.isConnected()).thenReturn(false);
+
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
+        Collections.sort(mMediaDevices, COMPARATOR);
+        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
+    }
+
     // 1.mInfoMediaDevice1:      Last Selected device
     // 2.mBluetoothMediaDevice1: CarKit device
     // 3.mInfoMediaDevice2:      * 2 times usage
@@ -242,7 +292,7 @@
     // 5.mBluetoothMediaDevice2: * 2 times usage
     // 6.mBluetoothMediaDevice3: * 1 time usage
     // 7.mPhoneMediaDevice:      * 0 time usage
-    // Order: 2 -> 1 -> 3 -> 5 -> 4 -> 6 -> 7
+    // Order: 7 -> 2 -> 1 -> 3 -> 5 -> 4 -> 6
     @Test
     public void compareTo_mixedDevices_carKitFirst() {
         when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
@@ -264,13 +314,55 @@
         mInfoMediaDevice1.connect();
 
         Collections.sort(mMediaDevices, COMPARATOR);
-        assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+        assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
+        assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice1);
+        assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice1);
+        assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice2);
+        assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice2);
+        assertThat(mMediaDevices.get(5)).isEqualTo(mInfoMediaDevice3);
+        assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice3);
+    }
+
+    // 1.mInfoMediaDevice1:      Last Selected device
+    // 2.mBluetoothMediaDevice1: CarKit device not connected
+    // 3.mInfoMediaDevice2:      * 2 times usage
+    // 4.mInfoMediaDevice3:      * 1 time usage
+    // 5.mBluetoothMediaDevice2: * 4 times usage not connected
+    // 6.mBluetoothMediaDevice3: * 1 time usage
+    // 7.mPhoneMediaDevice:      * 0 time usage
+    // Order: 7 -> 1 -> 3 -> 4 -> 6 -> 2 -> 5
+    @Test
+    public void compareTo_mixedDevices_connectDeviceFirst() {
+        when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
+        when(mDevice2.getBluetoothClass()).thenReturn(mHeadreeClass);
+        when(mDevice3.getBluetoothClass()).thenReturn(mHeadreeClass);
+        when(mCachedDevice1.isConnected()).thenReturn(false);
+        when(mCachedDevice2.isConnected()).thenReturn(false);
+        mMediaDevices.add(mBluetoothMediaDevice1);
+        mMediaDevices.add(mBluetoothMediaDevice2);
+        mMediaDevices.add(mBluetoothMediaDevice3);
+        mMediaDevices.add(mInfoMediaDevice1);
+        mMediaDevices.add(mInfoMediaDevice2);
+        mMediaDevices.add(mInfoMediaDevice3);
+        mMediaDevices.add(mPhoneMediaDevice);
+        mBluetoothMediaDevice3.connect();
+        mBluetoothMediaDevice2.connect();
+        mBluetoothMediaDevice2.connect();
+        mBluetoothMediaDevice2.connect();
+        mBluetoothMediaDevice2.connect();
+        mInfoMediaDevice3.connect();
+        mInfoMediaDevice2.connect();
+        mInfoMediaDevice2.connect();
+        mInfoMediaDevice1.connect();
+
+        Collections.sort(mMediaDevices, COMPARATOR);
+        assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
         assertThat(mMediaDevices.get(1)).isEqualTo(mInfoMediaDevice1);
         assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice2);
-        assertThat(mMediaDevices.get(3)).isEqualTo(mBluetoothMediaDevice2);
-        assertThat(mMediaDevices.get(4)).isEqualTo(mInfoMediaDevice3);
-        assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice3);
-        assertThat(mMediaDevices.get(6)).isEqualTo(mPhoneMediaDevice);
+        assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice3);
+        assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice3);
+        assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1);
+        assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2);
     }
 
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
index 98eccb5..ead2be4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -111,6 +111,15 @@
     }
 
     @Test
+    public void dispatchDataChanged_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchDataChanged();
+
+        verify(mCallback).onDeviceAttributesChanged();
+    }
+
+    @Test
     public void findMediaDevice_idExist_shouldReturnMediaDevice() {
         mMediaManager.mMediaDevices.add(mDevice);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 5ba33f5..50a6a9d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -23,6 +23,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 
+import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -97,4 +98,19 @@
 
         assertThat(mPhoneMediaDevice.connect()).isFalse();
     }
+
+    @Test
+    public void updateSummary_isActiveIsTrue_returnActiveString() {
+        mPhoneMediaDevice.updateSummary(true);
+
+        assertThat(mPhoneMediaDevice.getSummary())
+                .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+    }
+
+    @Test
+    public void updateSummary_notActive_returnEmpty() {
+        mPhoneMediaDevice.updateSummary(false);
+
+        assertThat(mPhoneMediaDevice.getSummary()).isEmpty();
+    }
 }
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f54f716..c83cb59 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -872,9 +872,6 @@
     <!-- Global actions grid layout -->
     <dimen name="global_actions_grid_side_margin">4dp</dimen>
 
-    <!-- Global actions panel -->
-    <dimen name="global_actions_panel_top_margin">85dp</dimen>
-
     <!-- The maximum offset in either direction that elements are moved horizontally to prevent
          burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_x">8dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b985b6b..4adece9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -287,7 +287,6 @@
         <item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
         <item name="passwordStyle">@style/PasswordTheme</item>
         <item name="backgroundProtectedStyle">@style/BackgroundProtectedStyle</item>
-        <item name="android:forceDarkAllowed">false</item>
 
         <!-- Needed for MediaRoute chooser dialog -->
         <item name="*android:isLightTheme">false</item>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 9b44066..b07f909 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1557,8 +1557,6 @@
                             new FrameLayout.LayoutParams(
                                     FrameLayout.LayoutParams.MATCH_PARENT,
                                     FrameLayout.LayoutParams.WRAP_CONTENT);
-                    panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
-                            com.android.systemui.R.dimen.global_actions_panel_top_margin);
                     panelContainer.addView(panelView, panelParams);
                     return panelContainer;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 7cbe1a3..059c3f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -22,10 +22,12 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.database.ContentObserver;
+import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
@@ -54,6 +56,7 @@
     private final StatusBarStateController mStatusBarStateController =
             Dependency.get(StatusBarStateController.class);
     private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
+    private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
 
     private final Context mContext;
     private final PowerManager mPowerManager;
@@ -73,17 +76,20 @@
         this(context,
                 (PowerManager) context.getSystemService(Context.POWER_SERVICE),
                 IDreamManager.Stub.asInterface(
-                        ServiceManager.checkService(DreamService.DREAM_SERVICE)));
+                        ServiceManager.checkService(DreamService.DREAM_SERVICE)),
+                new AmbientDisplayConfiguration(context));
     }
 
     @VisibleForTesting
     protected NotificationInterruptionStateProvider(
             Context context,
             PowerManager powerManager,
-            IDreamManager dreamManager) {
+            IDreamManager dreamManager,
+            AmbientDisplayConfiguration ambientDisplayConfiguration) {
         mContext = context;
         mPowerManager = powerManager;
         mDreamManager = dreamManager;
+        mAmbientDisplayConfiguration = ambientDisplayConfiguration;
     }
 
     /** Sets up late-binding dependencies for this component. */
@@ -232,6 +238,13 @@
     public boolean shouldPulse(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
+        if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+            if (DEBUG) {
+                Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey());
+            }
+            return false;
+        }
+
         if (!getShadeController().isDozing()) {
             if (DEBUG) {
                 Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 265fa2c..1949bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -90,6 +90,10 @@
      */
     public static final float GRADIENT_SCRIM_ALPHA = 0.2f;
     /**
+     * Scrim opacity when the phone is about to wake-up.
+     */
+    public static final float AOD2_SCRIM_ALPHA = 0.6f;
+    /**
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index ccf5e4e..2f161d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -133,11 +133,10 @@
                     || mPulseReason == DozeLog.PULSE_REASON_DOCKING
                     || mPulseReason == DozeLog.PULSE_REASON_INTENT) {
                 mCurrentBehindAlpha = previousState.getBehindAlpha();
-                mCurrentBehindTint = Color.BLACK;
             } else {
-                mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
-                mCurrentBehindTint = Color.TRANSPARENT;
+                mCurrentBehindAlpha = ScrimController.AOD2_SCRIM_ALPHA;
             }
+            mCurrentBehindTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
         }
     },
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1832265..60b1659 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3881,7 +3881,7 @@
                 return;
             }
 
-            boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
+            boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
             // Set the state to pulsing, so ScrimController will know what to do once we ask it to
             // execute the transition. The pulse callback will then be invoked when the scrims
             // are black, indicating that StatusBar is ready to present the rest of the UI.
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 7e5c3db..539851f 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
@@ -232,7 +232,7 @@
         // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
-        assertScrimTint(mScrimBehind, false /* tinted */);
+        assertScrimTint(mScrimBehind, true /* tinted */);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f8bfc54..1ded6c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -41,6 +41,7 @@
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -169,6 +170,8 @@
     private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
+    private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
@@ -205,7 +208,7 @@
 
         mNotificationInterruptionStateProvider =
                 new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
-                        mDreamManager);
+                        mDreamManager, mAmbientDisplayConfiguration);
         mDependency.injectTestDependency(NotificationInterruptionStateProvider.class,
                 mNotificationInterruptionStateProvider);
         mDependency.injectMockDependency(NavigationBarController.class);
@@ -641,10 +644,10 @@
     @Test
     public void testPulseWhileDozing_notifyAuthInterrupt() {
         HashSet<Integer> reasonsWantingAuth = new HashSet<>(
-                Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
+                Collections.singletonList(DozeLog.PULSE_REASON_NOTIFICATION));
         HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
                 Arrays.asList(DozeLog.PULSE_REASON_INTENT,
-                        DozeLog.PULSE_REASON_NOTIFICATION,
+                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
                         DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
                         DozeLog.REASON_SENSOR_PICKUP,
                         DozeLog.REASON_SENSOR_DOUBLE_TAP,
@@ -832,8 +835,9 @@
         public TestableNotificationInterruptionStateProvider(
                 Context context,
                 PowerManager powerManager,
-                IDreamManager dreamManager) {
-            super(context, powerManager, dreamManager);
+                IDreamManager dreamManager,
+                AmbientDisplayConfiguration ambientDisplayConfiguration) {
+            super(context, powerManager, dreamManager, ambientDisplayConfiguration);
             mUseHeadsUp = true;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 043b832..00d87c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.when;
 
 import android.os.SystemClock;
+import android.testing.TestableLooper;
 import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
@@ -35,13 +36,12 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper
 @SmallTest
-@Ignore
 public class StatusBarWindowViewTest extends SysuiTestCase {
 
     private StatusBarWindowView mView;
@@ -62,7 +62,6 @@
     }
 
     @Test
-    @Ignore
     public void testDragDownHelperCalledWhenDraggingDown() throws Exception {
         when(Dependency.get(StatusBarStateController.class).getState())
                 .thenReturn(StatusBarState.SHADE);
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f106ced..9f049cf 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1798,6 +1798,9 @@
   // Prediction horizon (in second) of Wifi usability score provided by external
   // system app
   optional int32 last_prediction_horizon_sec = 12 [default = -1];
+
+  // Whether screen status is on when WifiIsUnusableEvent happens.
+  optional bool screen_on = 13 [default = false];
 }
 
 message PasspointProfileTypeCount {
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 58dbea4..69b4672 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -32,6 +32,7 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Slog;
 
 import com.android.server.LocalServices;
@@ -63,7 +64,8 @@
 
     public ContentSuggestionsManagerService(Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
-                com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+                com.android.internal.R.string.config_defaultContentSuggestionsService),
+                UserManager.DISALLOW_CONTENT_SUGGESTIONS);
         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9fa0053..d6fdbe3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1803,7 +1803,7 @@
         synchronized (mRecords) {
             TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
                     Context.TELEPHONY_SERVICE);
-            mEmergencyNumberList = tm.getCurrentEmergencyNumberList();
+            mEmergencyNumberList = tm.getEmergencyNumberList();
 
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 5cca159..5d0fa26 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -111,6 +111,8 @@
     // intensity level. It's important that we apply the scaling on the delta between the two so
     // that the default intensity level applies no scaling to application provided effects.
     private final SparseArray<ScaleLevel> mScaleLevels;
+    private final LinkedList<VibrationInfo> mPreviousRingVibrations;
+    private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
     private final LinkedList<VibrationInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
     private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -354,6 +356,8 @@
         mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
 
+        mPreviousRingVibrations = new LinkedList<>();
+        mPreviousNotificationVibrations = new LinkedList<>();
         mPreviousVibrations = new LinkedList<>();
 
         IntentFilter filter = new IntentFilter();
@@ -620,10 +624,19 @@
     }
 
     private void addToPreviousVibrationsLocked(Vibration vib) {
-        if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
-            mPreviousVibrations.removeFirst();
+        final LinkedList<VibrationInfo> previousVibrations;
+        if (vib.isRingtone()) {
+            previousVibrations = mPreviousRingVibrations;
+        } else if (vib.isNotification()) {
+            previousVibrations = mPreviousNotificationVibrations;
+        } else {
+            previousVibrations = mPreviousVibrations;
         }
-        mPreviousVibrations.addLast(vib.toInfo());
+
+        if (previousVibrations.size() > mPreviousVibrationsLimit) {
+            previousVibrations.removeFirst();
+        }
+        previousVibrations.addLast(vib.toInfo());
     }
 
     @Override // Binder call
@@ -1355,6 +1368,18 @@
             pw.println("  mNotificationIntensity=" + mNotificationIntensity);
             pw.println("  mRingIntensity=" + mRingIntensity);
             pw.println("");
+            pw.println("  Previous ring vibrations:");
+            for (VibrationInfo info : mPreviousRingVibrations) {
+                pw.print("    ");
+                pw.println(info.toString());
+            }
+
+            pw.println("  Previous notification vibrations:");
+            for (VibrationInfo info : mPreviousNotificationVibrations) {
+                pw.print("    ");
+                pw.println(info.toString());
+            }
+
             pw.println("  Previous vibrations:");
             for (VibrationInfo info : mPreviousVibrations) {
                 pw.print("    ");
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 85322d6..57ce98c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1674,8 +1674,9 @@
 
     int runSwitchUser(PrintWriter pw) throws RemoteException {
         UserManager userManager = mInternal.mContext.getSystemService(UserManager.class);
-        if (!userManager.canSwitchUsers()) {
-            getErrPrintWriter().println("Error: disallowed switching user");
+        final int userSwitchable = userManager.getUserSwitchability();
+        if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
+            getErrPrintWriter().println("Error: " + userSwitchable);
             return -1;
         }
         String user = getNextArgRequired();
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index b0b1840..d029482 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -450,6 +450,8 @@
             return mCurrentBroadcast;
         }
 
+        final boolean someQueued = !mOrderedBroadcasts.isEmpty();
+
         BroadcastRecord next = null;
         if (!mAlarmBroadcasts.isEmpty()) {
             next = popLocked(mAlarmBroadcasts);
@@ -459,10 +461,18 @@
         }
 
         if (next == null && !mDeferredBroadcasts.isEmpty()) {
+            // We're going to deliver either:
+            // 1. the next "overdue" deferral; or
+            // 2. the next ordinary ordered broadcast; *or*
+            // 3. the next not-yet-overdue deferral.
+
             for (int i = 0; i < mDeferredBroadcasts.size(); i++) {
                 Deferrals d = mDeferredBroadcasts.get(i);
-                if (now < d.deferUntil) {
-                    // No more deferrals due
+                if (now < d.deferUntil && someQueued) {
+                    // stop looking when we haven't hit the next time-out boundary
+                    // but only if we have un-deferred broadcasts waiting,
+                    // otherwise we can deliver whatever deferred broadcast
+                    // is next available.
                     break;
                 }
 
@@ -483,7 +493,7 @@
             }
         }
 
-        if (next == null && !mOrderedBroadcasts.isEmpty()) {
+        if (next == null && someQueued) {
             next = mOrderedBroadcasts.remove(0);
             if (DEBUG_BROADCAST_DEFERRAL) {
                 Slog.i(TAG, "Next broadcast from main queue: " + next);
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 9789688..1ac09ad 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -70,9 +70,8 @@
     private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
     // Return values for #setCurrentProxyScriptUrl
-    enum ToSendOrNotToSendBroadcast {
-        DONT_SEND_BROADCAST, DO_SEND_BROADCAST
-    }
+    public static final boolean DONT_SEND_BROADCAST = false;
+    public static final boolean DO_SEND_BROADCAST = true;
 
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
@@ -176,11 +175,11 @@
      * @param proxy Proxy information that is about to be broadcast.
      * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
      */
-    synchronized ToSendOrNotToSendBroadcast setCurrentProxyScriptUrl(ProxyInfo proxy) {
+    synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
         if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
-                return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+                return DO_SEND_BROADCAST;
             }
             mPacUrl = proxy.getPacFileUrl();
             mCurrentDelay = DELAY_1;
@@ -188,7 +187,7 @@
             mHasDownloaded = false;
             getAlarmManager().cancel(mPacRefreshIntent);
             bind();
-            return ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST;
+            return DONT_SEND_BROADCAST;
         } else {
             getAlarmManager().cancel(mPacRefreshIntent);
             synchronized (mProxyLock) {
@@ -204,7 +203,7 @@
                     }
                 }
             }
-            return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+            return DO_SEND_BROADCAST;
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index a671287..e715890 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -208,8 +208,7 @@
     public void sendProxyBroadcast() {
         final ProxyInfo defaultProxy = getDefaultProxy();
         final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
-        if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)
-                == PacManager.ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST) {
+        if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
             return;
         }
         if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1f28a6c..6d7dff5 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -216,7 +216,7 @@
     private PackageManager mPackageManager;
 
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
-            SensorManager sensorManager, BrightnessMappingStrategy mapper,
+            SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
             int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
             int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
             long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
@@ -249,7 +249,7 @@
             new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
 
         if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
-            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+            mLightSensor = lightSensor;
         }
 
         mActivityTaskManager = ActivityTaskManager.getService();
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index af4db07..b0d8813 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -664,6 +664,12 @@
 
         private void updateDisplayModes(int displayId) {
             Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId);
+            if (d == null) {
+                // We can occasionally get a display added or changed event for a display that was
+                // subsequently removed, which means this returns null. Check this case and bail
+                // out early; if it gets re-attached we'll eventually get another call back for it.
+                return;
+            }
             DisplayInfo info = new DisplayInfo();
             d.getDisplayInfo(info);
             boolean changed = false;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 74cda9d..b79ead0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -44,6 +44,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -58,6 +59,7 @@
 import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
  * Controls the power state of the display.
@@ -474,10 +476,14 @@
             int shortTermModelTimeout = resources.getInteger(
                     com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
 
+            String lightSensorType = resources.getString(
+                    com.android.internal.R.string.config_displayLightSensorType);
+            Sensor lightSensor = findDisplayLightSensor(lightSensorType);
+
             mBrightnessMapper = BrightnessMappingStrategy.create(resources);
             if (mBrightnessMapper != null) {
                 mAutomaticBrightnessController = new AutomaticBrightnessController(this,
-                        handler.getLooper(), sensorManager, mBrightnessMapper,
+                        handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
                         lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                         initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
@@ -530,6 +536,19 @@
         mDisplayWhiteBalanceController = displayWhiteBalanceController;
     }
 
+    private Sensor findDisplayLightSensor(String sensorType) {
+        if (!TextUtils.isEmpty(sensorType)) {
+            List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+            for (int i = 0; i < sensors.size(); i++) {
+                Sensor sensor = sensors.get(i);
+                if (sensorType.equals(sensor.getStringType())) {
+                    return sensor;
+                }
+            }
+        }
+        return mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+    }
+
     /**
      * Returns true if the proximity sensor screen-off function is available.
      */
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2c361e1..150303a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4690,9 +4690,11 @@
     private int handleShellCommandEnableDisableInputMethod(
             @NonNull ShellCommand shellCommand, boolean enabled) {
         final String id = shellCommand.getNextArgRequired();
-
         final boolean previouslyEnabled;
         synchronized (mMethodMap) {
+            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+                return ShellCommandResult.SUCCESS;
+            }
             previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
         }
         final PrintWriter pr = shellCommand.getOutPrintWriter();
@@ -4714,6 +4716,9 @@
     private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
         final String id = shellCommand.getNextArgRequired();
         synchronized (mMethodMap) {
+            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+                return ShellCommandResult.SUCCESS;
+            }
             setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
         }
         final PrintWriter pr = shellCommand.getOutPrintWriter();
@@ -4732,6 +4737,9 @@
     @ShellCommandResult
     private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
         synchronized (mMethodMap) {
+            if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+                return ShellCommandResult.SUCCESS;
+            }
             final String nextIme;
             final List<InputMethodInfo> nextEnabledImes;
             hideCurrentInputLocked(0, null);
@@ -4769,6 +4777,22 @@
         }
     }
 
+    /**
+     * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
+     * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
+     * @return {@code true} if userId has debugging privileges.
+     * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
+     */
+    private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
+        if (mUserManager.hasUserRestriction(
+                UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
+            shellCommand.getErrPrintWriter().println("User #" + userId
+                    + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
+            return false;
+        }
+        return true;
+    }
+
     private static final class InputMethodPrivilegedOperationsImpl
             extends IInputMethodPrivilegedOperations.Stub {
         private final InputMethodManagerService mImms;
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 91b5234..0e9ee40 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -52,7 +52,6 @@
 
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
     private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
 
     // config.xml properties
@@ -191,8 +190,6 @@
             return Collections.EMPTY_LIST;
         }
 
-        // TODO(b/122856486): Validate proxy app names so that a system app or some popular app
-        //                    with location permission is not specified as a proxy app.
         ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
         for (String proxyApp : proxyAppsArray) {
             proxyApps.add(proxyApp);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 29030fa..c173d66 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -67,6 +67,7 @@
 import android.util.Log;
 import android.util.StatsLog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.location.GpsNetInitiatedHandler;
 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
@@ -890,12 +891,14 @@
         return GPS_POSITION_MODE_STANDALONE;
     }
 
-    private boolean handleEnable() {
-        if (DEBUG) Log.d(TAG, "handleEnable");
+    @GuardedBy("mLock")
+    private void handleEnableLocked() {
+        if (DEBUG) Log.d(TAG, "handleEnableLocked");
 
         boolean inited = native_init();
 
         if (inited) {
+            mEnabled = true;
             mSupportsXtra = native_supports_xtra();
 
             // TODO: remove the following native calls if we can make sure they are redundant.
@@ -912,15 +915,16 @@
             mGnssNavigationMessageProvider.onGpsEnabledChanged();
             mGnssBatchingProvider.enable();
         } else {
+            mEnabled = false;
             Log.w(TAG, "Failed to enable location provider");
         }
-
-        return inited;
     }
 
-    private void handleDisable() {
-        if (DEBUG) Log.d(TAG, "handleDisable");
+    @GuardedBy("mLock")
+    private void handleDisableLocked() {
+        if (DEBUG) Log.d(TAG, "handleDisableLocked");
 
+        mEnabled = false;
         updateClientUids(new WorkSource());
         stopNavigating();
         mAlarmManager.cancel(mWakeupIntent);
@@ -946,10 +950,9 @@
             }
 
             if (enabled) {
-                mEnabled = handleEnable();
+                handleEnableLocked();
             } else {
-                mEnabled = false;
-                handleDisable();
+                handleDisableLocked();
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 90d16cb..c06b03b 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -373,8 +373,8 @@
         networkAttributes = new NetworkAttributes();
         networkAttributes.mCapabilities = capabilities;
 
-        // TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
-        // not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
+        // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called
+        //       inside the asynchronous ConnectivityManager.NetworkCallback methods.
         NetworkInfo info = mConnMgr.getNetworkInfo(network);
         if (info != null) {
             networkAttributes.mApn = info.getExtraInfo();
@@ -387,8 +387,8 @@
     }
 
     private void handleSuplConnectionAvailable(Network network) {
-        // TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
-        // not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
+        // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called
+        //       inside the asynchronous ConnectivityManager.NetworkCallback methods.
         NetworkInfo info = mConnMgr.getNetworkInfo(network);
         String apn = null;
         if (info != null) {
@@ -509,8 +509,8 @@
         }
     }
 
-    // TODO(25876485): Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback
-    //                 interface which does not require setting route to host.
+    // TODO: Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback
+    //       interface which does not require setting route to host.
     private void setRouting() {
         boolean result = mConnMgr.requestRouteToHostAddress(
                 ConnectivityManager.TYPE_MOBILE_SUPL,
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index 20f872a..24ee389 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -18,7 +18,6 @@
 
 import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -32,11 +31,11 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.StatsLog;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -76,9 +75,9 @@
     private boolean mIsDeviceLocationSettingsEnabled;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
-    private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
-    private HashMap<String, Boolean> mProxyAppToLocationPermissions = new HashMap<>(
-            HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+    private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
+    private ArrayMap<String, Boolean> mProxyAppToLocationPermissions = new ArrayMap<>(
+            ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
 
     private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
             uid -> runOnHandler(() -> handlePermissionsChanged(uid));
@@ -97,10 +96,6 @@
     }
 
     void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
-        // NOTE: This class doesn't explicitly register and listen for SIM_STATE_CHANGED event
-        //       but rather piggy backs on the GnssLocationProvider SIM_STATE_CHANGED handling
-        //       so that the order of processing is preserved. GnssLocationProvider should
-        //       first load the new config parameters for the new SIM and then call this method.
         runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
     }
 
@@ -246,15 +241,7 @@
 
     // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
     private static class NfwNotification {
-        private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
-        private static final String KEY_OTHER_PROTOCOL_STACK_NAME = "OtherProtocolStackName";
-        private static final String KEY_REQUESTOR = "Requestor";
-        private static final String KEY_REQUESTOR_ID = "RequestorId";
-        private static final String KEY_RESPONSE_TYPE = "ResponseType";
-        private static final String KEY_IN_EMERGENCY_MODE = "InEmergencyMode";
-        private static final String KEY_IS_CACHED_LOCATION = "IsCachedLocation";
-
-        // This must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
+        // These must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
         private static final byte NFW_RESPONSE_TYPE_REJECTED = 0;
         private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
         private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
@@ -281,30 +268,14 @@
             mIsCachedLocation = isCachedLocation;
         }
 
-        private void copyFieldsToIntent(Intent intent) {
-            intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
-            if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
-                intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
-            }
-            intent.putExtra(KEY_REQUESTOR, mRequestor);
-            if (!TextUtils.isEmpty(mRequestorId)) {
-                intent.putExtra(KEY_REQUESTOR_ID, mRequestorId);
-            }
-            intent.putExtra(KEY_RESPONSE_TYPE, mResponseType);
-            intent.putExtra(KEY_IN_EMERGENCY_MODE, mInEmergencyMode);
-            if (mResponseType == NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED) {
-                intent.putExtra(KEY_IS_CACHED_LOCATION, mIsCachedLocation);
-            }
-        }
-
         @SuppressLint("DefaultLocale")
         public String toString() {
             return String.format(
-                    "[Notification] proxyAppPackageName: %s, protocolStack: %d"
-                            + ", otherProtocolStackName: %s, requestor: %d, requestorId: %s"
-                            + ", responseType: %d, inEmergencyMode: %b, isCachedLocation: %b",
-                    mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName,
-                    mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
+                    "{proxyAppPackageName: %s, protocolStack: %d, otherProtocolStackName: %s, "
+                            + "requestor: %d, requestorId: %s, responseType: %s, inEmergencyMode:"
+                            + " %b, isCachedLocation: %b}",
+                    mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName, mRequestor,
+                    mRequestorId, getResponseTypeAsString(), mInEmergencyMode, mIsCachedLocation);
         }
 
         private String getResponseTypeAsString() {
@@ -405,7 +376,7 @@
     }
 
     private void handleNfwNotification(NfwNotification nfwNotification) {
-        if (DEBUG) Log.d(TAG, nfwNotification.toString());
+        if (DEBUG) Log.d(TAG, "Non-framework location access notification: " + nfwNotification);
 
         final String proxyAppPackageName = nfwNotification.mProxyAppPackageName;
         Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
@@ -421,39 +392,27 @@
         logEvent(nfwNotification, isPermissionMismatched);
 
         if (TextUtils.isEmpty(proxyAppPackageName)) {
-            Log.e(TAG, "ProxyAppPackageName field is not set. Not sending intent to proxy app for "
-                    + nfwNotification);
+            Log.e(TAG, "ProxyAppPackageName field is not set. AppOps service not notified "
+                    + "for non-framework location access notification: " + nfwNotification);
             return;
         }
 
         if (isLocationPermissionEnabled == null) {
-            // App is not in the configured list.
-            Log.e(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+            Log.w(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
                     + "value specified for config parameter: "
-                    + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". Not sending intent to proxy app"
-                    + " for " + nfwNotification);
-            return;
-        }
-
-        // Send intent to non-framework location proxy app with notification information.
-        final Intent intent = new Intent(
-                proxyAppPackageName + NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX);
-        final String proxAppActivityName =
-                proxyAppPackageName + NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX;
-        intent.setClassName(proxyAppPackageName, proxAppActivityName);
-        intent.setType(NFW_INTENT_TYPE);
-        nfwNotification.copyFieldsToIntent(intent);
-
-        // Check if the proxy app is still installed.
-        final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
-        if (clsAppUid == null || intent.resolveActivity(mPackageManager) == null) {
-            Log.i(TAG, "Proxy application " + proxyAppPackageName + " and/or activity "
-                    + proxAppActivityName + " is not found. Not sending"
-                    + " intent to proxy app for " + nfwNotification);
+                    + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". AppOps service not notified "
+                    + "for non-framework location access notification: " + nfwNotification);
             return;
         }
 
         // Display location icon attributed to this proxy app.
+        final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
+        if (clsAppUid == null) {
+            Log.e(TAG, "Proxy app " + proxyAppPackageName + " is not found. AppOps service not "
+                    + "notified for non-framework location access notification: "
+                    + nfwNotification);
+            return;
+        }
         mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, clsAppUid, proxyAppPackageName);
 
         // Log proxy app permission mismatch between framework and GNSS HAL.
@@ -461,18 +420,8 @@
             Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPackageName
                     + " location permission is set to " + isLocationPermissionEnabled
                     + " but GNSS non-framework location access response type is "
-                    + nfwNotification.getResponseTypeAsString() + " for " + nfwNotification);
-        }
-
-        // Notify proxy app.
-        try {
-            if (DEBUG) {
-                Log.d(TAG, "Sending non-framework location access notification intent: " + intent);
-            }
-            mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid(clsAppUid));
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "Activity not found. Failed to send non-framework location access"
-                    + " notification intent to proxy app activity: " + proxAppActivityName);
+                    + nfwNotification.getResponseTypeAsString() + " for notification: "
+                    + nfwNotification);
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index b6995db..a53ab84 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -21,6 +21,7 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
@@ -2648,7 +2649,8 @@
         }
     }
 
-    private long addEscrowToken(byte[] token, int userId) throws RemoteException {
+    private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback)
+            throws RemoteException {
         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
         synchronized (mSpManager) {
             enableSyntheticPasswordLocked();
@@ -2672,7 +2674,7 @@
                     throw new SecurityException("Escrow token is disabled on the current user");
                 }
             }
-            long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
+            long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId, callback);
             if (auth != null) {
                 mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
             }
@@ -2943,9 +2945,10 @@
     private final class LocalService extends LockSettingsInternal {
 
         @Override
-        public long addEscrowToken(byte[] token, int userId) {
+        public long addEscrowToken(byte[] token, int userId,
+                EscrowTokenStateChangeCallback callback) {
             try {
-                return LockSettingsService.this.addEscrowToken(token, userId);
+                return LockSettingsService.this.addEscrowToken(token, userId, callback);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index dbcfbcd..142ad53 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.locksettings;
 
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicyManager;
@@ -281,6 +283,7 @@
         byte[] secdiscardableOnDisk;
         byte[] weaverSecret;
         byte[] aggregatedSecret;
+        EscrowTokenStateChangeCallback mCallback;
     }
 
     private final Context mContext;
@@ -746,7 +749,12 @@
 
     private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();
 
-    public long createTokenBasedSyntheticPassword(byte[] token, int userId) {
+    /**
+     * Create a token based Synthetic password for the given user.
+     * @return
+     */
+    public long createTokenBasedSyntheticPassword(byte[] token, int userId,
+            @Nullable EscrowTokenStateChangeCallback changeCallback) {
         long handle = generateHandle();
         if (!tokenMap.containsKey(userId)) {
             tokenMap.put(userId, new ArrayMap<>());
@@ -762,6 +770,7 @@
             tokenData.weaverSecret = null;
         }
         tokenData.aggregatedSecret = transformUnderSecdiscardable(token, secdiscardable);
+        tokenData.mCallback = changeCallback;
 
         tokenMap.get(userId).put(handle, tokenData);
         return handle;
@@ -810,6 +819,9 @@
         createSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED, authToken,
                 tokenData.aggregatedSecret, 0L, userId);
         tokenMap.get(userId).remove(handle);
+        if (tokenData.mCallback != null) {
+            tokenData.mCallback.onEscrowTokenActivated(handle, userId);
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 7a87a57..0c0c23a 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1112,7 +1112,7 @@
                             binder.linkToDeath(info, 0);
                             added = mServices.add(info);
                         } catch (RemoteException e) {
-                            // already dead
+                            Slog.e(TAG, "Failed to linkToDeath, already dead", e);
                         }
                     }
                     if (added) {
@@ -1144,6 +1144,11 @@
                         }
                     }
                 }
+
+                @Override
+                public void onNullBinding(ComponentName name) {
+                    Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
+                }
             };
             if (!mContext.bindServiceAsUser(intent,
                     serviceConnection,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d25360a..88e697c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -251,7 +251,6 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
-import java.util.function.Predicate;
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
@@ -759,7 +758,7 @@
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r == null) {
-                    Log.w(TAG, "No notification with key: " + key);
+                    Slog.w(TAG, "No notification with key: " + key);
                     return;
                 }
                 final long now = System.currentTimeMillis();
@@ -789,7 +788,7 @@
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r == null) {
-                    Log.w(TAG, "No notification with key: " + key);
+                    Slog.w(TAG, "No notification with key: " + key);
                     return;
                 }
                 final long now = System.currentTimeMillis();
@@ -3133,7 +3132,7 @@
                 synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     if (info.supportsProfiles()) {
-                        Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+                        Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
                                 + "from " + info.component
                                 + " use cancelNotification(key) instead.");
                     } else {
@@ -4553,7 +4552,7 @@
                     + ", incomingUserId=" + incomingUserId
                     + ", notificationUid=" + notificationUid
                     + ", notification=" + notification;
-            Log.e(TAG, noChannelStr);
+            Slog.e(TAG, noChannelStr);
             boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
                     == NotificationManager.IMPORTANCE_NONE;
 
@@ -4650,7 +4649,7 @@
                     android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
             if (fullscreenIntentPermission != PERMISSION_GRANTED) {
                 notification.fullScreenIntent = null;
-                Log.w(TAG, "Package " + pkg +
+                Slog.w(TAG, "Package " + pkg +
                         ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
             }
         }
@@ -5179,7 +5178,7 @@
         // Ignore summary updates because we don't display most of the information.
         if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is not interruptive: summary");
             }
             return false;
@@ -5187,7 +5186,7 @@
 
         if (old == null) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is interruptive: new notification");
             }
             return true;
@@ -5195,7 +5194,7 @@
 
         if (r == null) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is not interruptive: null");
             }
             return false;
@@ -5206,7 +5205,7 @@
 
         if (oldN.extras == null || newN.extras == null) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is not interruptive: no extras");
             }
             return false;
@@ -5216,7 +5215,7 @@
         // consider them one 'session'. Count them for everything else.
         if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is not interruptive: foreground service");
             }
             return false;
@@ -5226,11 +5225,11 @@
         final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
         if (!Objects.equals(oldTitle, newTitle)) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is interruptive: changed title");
-                Log.v(TAG, "INTERRUPTIVENESS: " + String.format("   old title: %s (%s@0x%08x)",
+                Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old title: %s (%s@0x%08x)",
                         oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
-                Log.v(TAG, "INTERRUPTIVENESS: " + String.format("   new title: %s (%s@0x%08x)",
+                Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new title: %s (%s@0x%08x)",
                         newTitle, newTitle.getClass(), newTitle.hashCode()));
             }
             return true;
@@ -5240,18 +5239,18 @@
         final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
         if (!Objects.equals(oldText, newText)) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         + r.getKey() + " is interruptive: changed text");
-                Log.v(TAG, "INTERRUPTIVENESS: " + String.format("   old text: %s (%s@0x%08x)",
+                Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   old text: %s (%s@0x%08x)",
                         oldText, oldText.getClass(), oldText.hashCode()));
-                Log.v(TAG, "INTERRUPTIVENESS: " + String.format("   new text: %s (%s@0x%08x)",
+                Slog.v(TAG, "INTERRUPTIVENESS: " + String.format("   new text: %s (%s@0x%08x)",
                         newText, newText.getClass(), newText.hashCode()));
             }
             return true;
         }
         if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                     +  r.getKey() + " is interruptive: completed progress");
             }
             return true;
@@ -5259,7 +5258,7 @@
         // Actions
         if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
             if (DEBUG_INTERRUPTIVENESS) {
-                Log.v(TAG, "INTERRUPTIVENESS: "
+                Slog.v(TAG, "INTERRUPTIVENESS: "
                         +  r.getKey() + " is interruptive: changed actions");
             }
             return true;
@@ -5272,7 +5271,7 @@
             // Style based comparisons
             if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
                 if (DEBUG_INTERRUPTIVENESS) {
-                    Log.v(TAG, "INTERRUPTIVENESS: "
+                    Slog.v(TAG, "INTERRUPTIVENESS: "
                             +  r.getKey() + " is interruptive: styles differ");
                 }
                 return true;
@@ -5281,7 +5280,7 @@
             // Remote views
             if (Notification.areRemoteViewsChanged(oldB, newB)) {
                 if (DEBUG_INTERRUPTIVENESS) {
-                    Log.v(TAG, "INTERRUPTIVENESS: "
+                    Slog.v(TAG, "INTERRUPTIVENESS: "
                             +  r.getKey() + " is interruptive: remoteviews differ");
                 }
                 return true;
@@ -5510,12 +5509,12 @@
             // Ignore summary updates because we don't display most of the information.
             if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
                 if (DEBUG_INTERRUPTIVENESS) {
-                    Log.v(TAG, "INTERRUPTIVENESS: "
+                    Slog.v(TAG, "INTERRUPTIVENESS: "
                             + record.getKey() + " is not interruptive: summary");
                 }
             } else {
                 if (DEBUG_INTERRUPTIVENESS) {
-                    Log.v(TAG, "INTERRUPTIVENESS: "
+                    Slog.v(TAG, "INTERRUPTIVENESS: "
                             + record.getKey() + " is interruptive: alerted");
                 }
                 record.setInterruptive(true);
@@ -6603,7 +6602,7 @@
         String pkg = r.sbn.getPackageName();
 
         if (pkg == null) {
-            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
+            if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
             return;
         }
 
@@ -6862,7 +6861,7 @@
                 return;
             }
         } catch (RemoteException re) {
-            if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
+            if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
                     + "restrictions check thus the check will be done anyway");
         }
         if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
@@ -7104,7 +7103,7 @@
                     canUseManagedServices = false;
                 }
             } catch (RemoteException e) {
-                Log.e(TAG, "can't talk to pm", e);
+                Slog.e(TAG, "can't talk to pm", e);
             }
         }
 
@@ -7247,21 +7246,29 @@
             try {
                 assistant.onNotificationsSeen(keys);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
+                Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
             }
         }
 
         @GuardedBy("mNotificationLock")
         private void onNotificationEnqueuedLocked(final NotificationRecord r) {
+            final boolean debug = isVerboseLogEnabled();
+            if (debug) {
+                Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
+            }
             final StatusBarNotification sbn = r.sbn;
             notifyAssistantLocked(
                     sbn,
                     true /* sameUserOnly */,
                     (assistant, sbnHolder) -> {
                         try {
+                            if (debug) {
+                                Slog.v(TAG,
+                                        "calling onNotificationEnqueuedWithChannel " + sbnHolder);
+                            }
                             assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
                         }
                     });
         }
@@ -7279,7 +7286,7 @@
                         try {
                             assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
                         }
                     });
         }
@@ -7295,7 +7302,7 @@
                         try {
                             assistant.onNotificationDirectReply(key);
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
                         }
                     });
         }
@@ -7316,7 +7323,7 @@
                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
                                             : NotificationAssistantService.SOURCE_FROM_APP);
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
                         }
                     });
         }
@@ -7338,7 +7345,7 @@
                                             ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
                                             : NotificationAssistantService.SOURCE_FROM_APP);
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
                         }
                     });
         }
@@ -7358,7 +7365,7 @@
                             assistant.onNotificationSnoozedUntilContext(
                                     sbnHolder, snoozeCriterionId);
                         } catch (RemoteException ex) {
-                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+                            Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
                         }
                     });
         }
@@ -7380,9 +7387,19 @@
             TrimCache trimCache = new TrimCache(sbn);
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
+
+            final boolean debug = isVerboseLogEnabled();
+            if (debug) {
+                Slog.v(TAG,
+                        "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
+                                + sameUserOnly + "], callback = [" + callback + "]");
+            }
             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                 boolean sbnVisible = isVisibleToListener(sbn, info)
                         && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
+                if (debug) {
+                    Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
+                }
                 if (!sbnVisible) {
                     continue;
                 }
@@ -7436,6 +7453,10 @@
                 }
             }
         }
+
+        private boolean isVerboseLogEnabled() {
+            return Log.isLoggable("notification_assistant", Log.VERBOSE);
+        }
     }
 
     public class NotificationListeners extends ManagedServices {
@@ -7530,7 +7551,7 @@
                      try {
                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
                     } catch (RemoteException ex) {
-                        Log.e(TAG, "unable to notify listener "
+                        Slog.e(TAG, "unable to notify listener "
                                 + "(hideSilentStatusIcons): " + listener, ex);
                     }
                 });
@@ -7824,7 +7845,7 @@
             try {
                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
             }
         }
 
@@ -7838,7 +7859,7 @@
             try {
                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
             }
         }
 
@@ -7848,7 +7869,7 @@
             try {
                 listener.onNotificationRankingUpdate(rankingUpdate);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
             }
         }
 
@@ -7857,7 +7878,7 @@
             try {
                 listener.onListenerHintsChanged(hints);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
             }
         }
 
@@ -7867,7 +7888,7 @@
             try {
                 listener.onInterruptionFilterChanged(interruptionFilter);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
             }
         }
 
@@ -7878,7 +7899,7 @@
             try {
                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
             }
         }
 
@@ -7889,7 +7910,7 @@
             try {
                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
             } catch (RemoteException ex) {
-                Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
             }
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 48818f5..46ce4bf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -637,25 +637,17 @@
                     final ArrayList<String> people =
                             adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
                     setPeopleOverride(people);
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_PEOPLE, people.size()));
                 }
                 if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
                     final ArrayList<SnoozeCriterion> snoozeCriterionList =
                             adjustment.getSignals().getParcelableArrayList(
                                     Adjustment.KEY_SNOOZE_CRITERIA);
                     setSnoozeCriteria(snoozeCriterionList);
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SNOOZE_CRITERIA,
-                                    snoozeCriterionList.size()));
                 }
                 if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
                     final String groupOverrideKey =
                             adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
                     setOverrideGroupKey(groupOverrideKey);
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_GROUP_KEY,
-                                    groupOverrideKey));
                 }
                 if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
                     // Only allow user sentiment update from assistant if user hasn't already
@@ -664,32 +656,20 @@
                             && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
                         setUserSentiment(adjustment.getSignals().getInt(
                                 Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
-                        MetricsLogger.action(getAdjustmentLogMaker()
-                                .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_USER_SENTIMENT,
-                                        getUserSentiment()));
                     }
                 }
                 if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
                     setSystemGeneratedSmartActions(
                             signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS,
-                                    getSystemGeneratedSmartActions().size()));
                 }
                 if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
                     setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
-                                    getSmartReplies().size()));
                 }
                 if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
                     int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
                     importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
                     importance = Math.min(IMPORTANCE_HIGH, importance);
                     setAssistantImportance(importance);
-                    MetricsLogger.action(getAdjustmentLogMaker()
-                            .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_IMPORTANCE,
-                                    importance));
                 }
             }
             // We have now gotten all the information out of the adjustments and can forget them.
@@ -1280,12 +1260,6 @@
         return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
     }
 
-    public LogMaker getAdjustmentLogMaker() {
-        return getLogMaker()
-                .setCategory(MetricsEvent.NOTIFICATION_ITEM)
-                .setType(MetricsEvent.TYPE_NOTIFICATION_ASSISTANT_ADJUSTMENT);
-    }
-
     @VisibleForTesting
     static final class Light {
         public final int color;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 22a85eb..4ee6eaf 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -35,6 +35,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.Signature;
 import android.content.rollback.IRollbackManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -117,9 +118,11 @@
         final PackageInfo packageInfo = mApexManager.getActivePackage(packageName);
 
         if (packageInfo == null) {
-            // TODO: What is the right thing to do here ? This implies there's no active package
-            // with the given name. This should never be the case in production (where we only
-            // accept updates to existing APEXes) but may be required for testing.
+            // Only allow installing new apexes if on a debuggable build.
+            if (!Build.IS_DEBUGGABLE) {
+                Slog.w(TAG, "Attempted to install new apex " + packageName + " on user build");
+                return false;
+            }
             return true;
         }
 
@@ -498,19 +501,21 @@
             Slog.w(TAG, "Cannot abort applied session!");
             return;
         }
-        if (isStagedSessionFinalized(session.sessionId)) {
-            Slog.w(TAG, "Cannot abort session because it is not active or APEXD is not reachable");
-            return;
-        }
-
-        mApexManager.abortActiveSession();
-
         abortSession(session);
+
+        boolean hasApex = sessionContainsApex(session);
+        if (hasApex) {
+            ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+            if (apexSession == null || isApexSessionFinalized(apexSession)) {
+                Slog.w(TAG,
+                        "Cannot abort session because it is not active or APEXD is not reachable");
+                return;
+            }
+            mApexManager.abortActiveSession();
+        }
     }
 
-    private boolean isStagedSessionFinalized(int sessionId) {
-        ApexSessionInfo session = mApexManager.getStagedSessionInfo(sessionId);
-
+    private boolean isApexSessionFinalized(ApexSessionInfo session) {
         /* checking if the session is in a final state, i.e., not active anymore */
         return session.isUnknown || session.isActivationFailed || session.isSuccess
                 || session.isRolledBack;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 7e4365d..ae4ff03 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -120,6 +120,7 @@
             UserManager.DISALLOW_UNMUTE_DEVICE,
             UserManager.DISALLOW_AUTOFILL,
             UserManager.DISALLOW_CONTENT_CAPTURE,
+            UserManager.DISALLOW_CONTENT_SUGGESTIONS,
             UserManager.DISALLOW_USER_SWITCH,
             UserManager.DISALLOW_UNIFIED_PASSWORD,
             UserManager.DISALLOW_CONFIG_LOCATION,
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 7d03d82..16d11ef 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -89,9 +89,6 @@
     @GuardedBy("mLock")
     private ArrayMap<String, Temperature> mTemperatureMap = new ArrayMap<>();
 
-    /** Local PMS handle. */
-    private final PowerManager mPowerManager;
-
     /** HAL wrapper. */
     private ThermalHalWrapper mHalWrapper;
 
@@ -109,7 +106,6 @@
     @VisibleForTesting
     ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) {
         super(context);
-        mPowerManager = context.getSystemService(PowerManager.class);
         mHalWrapper = halWrapper;
         // Initialize to invalid to send status onActivityManagerReady
         mStatus = INVALID_THROTTLING;
@@ -254,10 +250,11 @@
         }
     }
 
-    private void shutdownIfNeededLocked(Temperature temperature) {
+    private void shutdownIfNeeded(Temperature temperature) {
         if (temperature.getStatus() != Temperature.THROTTLING_SHUTDOWN) {
             return;
         }
+        final PowerManager powerManager = getContext().getSystemService(PowerManager.class);
         switch (temperature.getType()) {
             case Temperature.TYPE_CPU:
                 // Fall through
@@ -266,17 +263,17 @@
             case Temperature.TYPE_NPU:
                 // Fall through
             case Temperature.TYPE_SKIN:
-                mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
+                powerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
                 break;
             case Temperature.TYPE_BATTERY:
-                mPowerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
+                powerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
                 break;
         }
     }
 
     private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
+        shutdownIfNeeded(temperature);
         synchronized (mLock) {
-            shutdownIfNeededLocked(temperature);
             Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
             if (old != null) {
                 if (old.getStatus() != temperature.getStatus()) {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 059e6d7..f4e10ed 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -27,7 +27,6 @@
 import android.app.AppOpsManager;
 import android.app.role.IOnRoleHoldersChangedListener;
 import android.app.role.IRoleManager;
-import android.app.role.IRoleManagerCallback;
 import android.app.role.RoleControllerManager;
 import android.app.role.RoleManager;
 import android.content.BroadcastReceiver;
@@ -245,14 +244,11 @@
             // Run grants again
             Slog.i(LOG_TAG, "Granting default permissions...");
             CompletableFuture<Void> result = new CompletableFuture<>();
-            getOrCreateControllerService(userId).onGrantDefaultRoles(
-                    new IRoleManagerCallback.Stub() {
-                        @Override
-                        public void onSuccess() {
+            getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(),
+                    successful -> {
+                        if (successful) {
                             result.complete(null);
-                        }
-                        @Override
-                        public void onFailure() {
+                        } else {
                             result.completeExceptionally(new RuntimeException());
                         }
                     });
@@ -434,11 +430,12 @@
 
         @Override
         public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             int callingUid = getCallingUid();
             mAppOpsManager.checkPackage(callingUid, packageName);
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
             int userId = UserHandle.getUserId(callingUid);
             ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
             if (roleHolders == null) {
@@ -450,7 +447,6 @@
         @NonNull
         @Override
         public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
             if (!mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return Collections.emptyList();
@@ -459,6 +455,8 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "getRoleHoldersAsUser");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+
             ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
             if (roleHolders == null) {
                 return Collections.emptyList();
@@ -469,10 +467,7 @@
         @Override
         public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
-                @NonNull IRoleManagerCallback callback) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-            Preconditions.checkNotNull(callback, "callback cannot be null");
+                @NonNull RemoteCallback callback) {
             if (!mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
@@ -481,6 +476,10 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "addRoleHolderAsUser");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+            Preconditions.checkNotNull(callback, "callback cannot be null");
+
             getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags,
                     callback);
         }
@@ -488,10 +487,7 @@
         @Override
         public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
-                @NonNull IRoleManagerCallback callback) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-            Preconditions.checkNotNull(callback, "callback cannot be null");
+                @NonNull RemoteCallback callback) {
             if (!mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
@@ -500,6 +496,10 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "removeRoleHolderAsUser");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+            Preconditions.checkNotNull(callback, "callback cannot be null");
+
             getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags,
                     callback);
         }
@@ -507,9 +507,7 @@
         @Override
         public void clearRoleHoldersAsUser(@NonNull String roleName,
                 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
-                @NonNull IRoleManagerCallback callback) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkNotNull(callback, "callback cannot be null");
+                @NonNull RemoteCallback callback) {
             if (!mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
@@ -518,13 +516,15 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "clearRoleHoldersAsUser");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkNotNull(callback, "callback cannot be null");
+
             getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback);
         }
 
         @Override
         public void addOnRoleHoldersChangedListenerAsUser(
                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
-            Preconditions.checkNotNull(listener, "listener cannot be null");
             if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
@@ -533,6 +533,8 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "addOnRoleHoldersChangedListenerAsUser");
 
+            Preconditions.checkNotNull(listener, "listener cannot be null");
+
             RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
                     userId);
             listeners.register(listener);
@@ -541,7 +543,6 @@
         @Override
         public void removeOnRoleHoldersChangedListenerAsUser(
                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
-            Preconditions.checkNotNull(listener, "listener cannot be null");
             if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
@@ -550,6 +551,8 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "removeOnRoleHoldersChangedListenerAsUser");
 
+            Preconditions.checkNotNull(listener, "listener cannot be null");
+
             RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
             if (listener == null) {
                 return;
@@ -559,11 +562,12 @@
 
         @Override
         public void setRoleNamesFromController(@NonNull List<String> roleNames) {
-            Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
             getContext().enforceCallingOrSelfPermission(
                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
                     "setRoleNamesFromController");
 
+            Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+
             int userId = UserHandle.getCallingUserId();
             getOrCreateUserState(userId).setRoleNames(roleNames);
         }
@@ -571,12 +575,13 @@
         @Override
         public boolean addRoleHolderFromController(@NonNull String roleName,
                 @NonNull String packageName) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             getContext().enforceCallingOrSelfPermission(
                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
                     "addRoleHolderFromController");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
             int userId = UserHandle.getCallingUserId();
             return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
         }
@@ -584,23 +589,25 @@
         @Override
         public boolean removeRoleHolderFromController(@NonNull String roleName,
                 @NonNull String packageName) {
-            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             getContext().enforceCallingOrSelfPermission(
                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
                     "removeRoleHolderFromController");
 
+            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
             int userId = UserHandle.getCallingUserId();
             return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
         }
 
         @Override
         public List<String> getHeldRolesFromController(@NonNull String packageName) {
-            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             getContext().enforceCallingOrSelfPermission(
                     RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
                     "getRolesHeldFromController");
 
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
             int userId = UserHandle.getCallingUserId();
             return getOrCreateUserState(userId).getHeldRoles(packageName);
         }
@@ -728,16 +735,14 @@
         @Override
         public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
             CompletableFuture<Void> future = new CompletableFuture<>();
-            IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() {
+            RemoteCallback callback = new RemoteCallback(result -> {
+                boolean successful = result != null;
+                if (successful) {
                     future.complete(null);
-                }
-                @Override
-                public void onFailure() {
+                } else {
                     future.completeExceptionally(new RuntimeException());
                 }
-            };
+            });
             if (packageName != null) {
                 getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                         packageName, 0, callback);
@@ -756,14 +761,12 @@
 
         @Override
         public void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId) {
-            IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() {}
-                @Override
-                public void onFailure() {
+            RemoteCallback callback = new RemoteCallback(result -> {
+                boolean successful = result != null;
+                if (!successful) {
                     Slog.e(LOG_TAG, "Failed to set default browser: " + packageName);
                 }
-            };
+            });
             if (packageName != null) {
                 getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                         packageName, 0, callback);
@@ -785,14 +788,12 @@
 
         @Override
         public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId) {
-            IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
-                @Override
-                public void onSuccess() {}
-                @Override
-                public void onFailure() {
+            RemoteCallback callback = new RemoteCallback(result -> {
+                boolean successful = result != null;
+                if (!successful) {
                     Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
                 }
-            };
+            });
             if (packageName != null) {
                 getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
                         packageName, 0, callback);
diff --git a/services/core/java/com/android/server/role/RoleManagerShellCommand.java b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
index 00021d7..b26a070 100644
--- a/services/core/java/com/android/server/role/RoleManagerShellCommand.java
+++ b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.role.IRoleManager;
-import android.app.role.IRoleManagerCallback;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -38,14 +38,23 @@
         mRoleManager = roleManager;
     }
 
-    private class Callback extends IRoleManagerCallback.Stub {
+    private class CallbackFuture extends CompletableFuture<Void> {
 
         @NonNull
-        private final CompletableFuture<Void> mResult = new CompletableFuture<>();
+        public RemoteCallback createCallback() {
+            return new RemoteCallback(result -> {
+                boolean successful = result != null;
+                if (successful) {
+                    complete(null);
+                } else {
+                    completeExceptionally(new RuntimeException("Failed"));
+                }
+            });
+        }
 
         public int waitForResult() {
             try {
-                mResult.get(5, TimeUnit.SECONDS);
+                get(5, TimeUnit.SECONDS);
                 return 0;
             } catch (Exception e) {
                 getErrPrintWriter().println("Error: see logcat for details.\n"
@@ -53,16 +62,6 @@
                 return -1;
             }
         }
-
-        @Override
-        public void onSuccess() {
-            mResult.complete(null);
-        }
-
-        @Override
-        public void onFailure() {
-            mResult.completeExceptionally(new RuntimeException("Failed"));
-        }
     }
 
     @Override
@@ -112,9 +111,10 @@
         String packageName = getNextArgRequired();
         int flags = getFlagsMaybe();
 
-        Callback callback = new Callback();
-        mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId, callback);
-        return callback.waitForResult();
+        CallbackFuture future = new CallbackFuture();
+        mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId,
+                future.createCallback());
+        return future.waitForResult();
     }
 
     private int runRemoveRoleHolder() throws RemoteException {
@@ -123,9 +123,10 @@
         String packageName = getNextArgRequired();
         int flags = getFlagsMaybe();
 
-        Callback callback = new Callback();
-        mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId, callback);
-        return callback.waitForResult();
+        CallbackFuture future = new CallbackFuture();
+        mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId,
+                future.createCallback());
+        return future.waitForResult();
     }
 
     private int runClearRoleHolders() throws RemoteException {
@@ -133,9 +134,9 @@
         String roleName = getNextArgRequired();
         int flags = getFlagsMaybe();
 
-        Callback callback = new Callback();
-        mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, callback);
-        return callback.waitForResult();
+        CallbackFuture future = new CallbackFuture();
+        mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, future.createCallback());
+        return future.waitForResult();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
index 6be93a0..921b754 100644
--- a/services/core/java/com/android/server/rollback/TEST_MAPPING
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -5,6 +5,14 @@
     },
     {
       "name": "StagedRollbackTest"
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.rollback"
+        }
+      ]
     }
   ]
 }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 28fee4e..4614355 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -43,8 +43,6 @@
 import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.policy.IKeyguardDismissCallback;
-
 import java.util.Collections;
 import java.util.List;
 
@@ -495,6 +493,21 @@
         }
     }
 
+    /**
+     * @see android.service.trust.TrustAgentService#onTokenStateReceived()
+     *
+     */
+    public void onEscrowTokenActivated(long handle, int userId) {
+        if (DEBUG) Slog.d(TAG, "onEscrowTokenActivated: " + handle + " user: " + userId);
+        if (mTrustAgentService != null) {
+            try {
+                mTrustAgentService.onTokenStateReceived(handle,
+                        TrustAgentService.TOKEN_STATE_ACTIVE);
+            } catch (RemoteException e) {
+                onError(e);
+            }
+        }
+    }
     private void setCallback(ITrustAgentServiceCallback callback) {
         try {
             if (mTrustAgentService != null) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c7044a1..3a39053 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -409,7 +409,10 @@
     }
 
     public long addEscrowToken(byte[] token, int userId) {
-        return mLockPatternUtils.addEscrowToken(token, userId);
+        return mLockPatternUtils.addEscrowToken(token, userId,
+                (long handle, int userid) -> {
+                    dispatchEscrowTokenActivatedLocked(handle, userid);
+                });
     }
 
     public boolean removeEscrowToken(long handle, int userId) {
@@ -662,6 +665,15 @@
         }
     }
 
+    private void dispatchEscrowTokenActivatedLocked(long handle, int userId) {
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo agent = mActiveAgents.valueAt(i);
+            if (agent.userId == userId) {
+                agent.agent.onEscrowTokenActivated(handle, userId);
+            }
+        }
+    }
+
     void updateDevicePolicyFeatures() {
         boolean changed = false;
         for (int i = 0; i < mActiveAgents.size(); i++) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36251f5..d7922b15 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -13352,8 +13352,8 @@
                 if (policy.mPasswordTokenHandle != 0) {
                     mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle);
                 }
-
-                policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token, userHandle);
+                policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token,
+                        userHandle, /*EscrowTokenStateChangeCallback*/ null);
                 saveSettingsLocked(userHandle);
                 return policy.mPasswordTokenHandle != 0;
             } finally {
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index eed01ae..a8f4a77 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -42,7 +42,6 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
 /**
@@ -53,6 +52,7 @@
     private static final String TAG = NetworkStackClient.class.getSimpleName();
 
     private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
+    private static final String IN_PROCESS_SUFFIX = ".InProcess";
 
     private static NetworkStackClient sInstance;
 
@@ -175,42 +175,50 @@
     public void start(Context context) {
         log("Starting network stack");
         mNetworkStackStartRequested = true;
-        // Try to bind in-process if the library is available
-        IBinder connector = null;
-        try {
-            final Class service = Class.forName(
-                    "com.android.server.NetworkStackService",
-                    true /* initialize */,
-                    context.getClassLoader());
-            connector = (IBinder) service.getMethod("makeConnector", Context.class)
-                    .invoke(null, context);
-        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
-            logWtf("Could not create network stack connector from NetworkStackService", e);
-            // TODO: crash/reboot system here ?
-            return;
-        } catch (ClassNotFoundException e) {
-            // Normal behavior if stack is provided by the app: fall through
+
+        final PackageManager pm = context.getPackageManager();
+
+        // Try to bind in-process if the device was shipped with an in-process version
+        Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
+
+        // Otherwise use the updatable module version
+        if (intent == null) {
+            intent = getNetworkStackIntent(pm, false /* inSystemProcess */);
+            log("Starting network stack process");
+        } else {
+            log("Starting network stack in-process");
         }
 
-        // In-process network stack. Add the service to the service manager here.
-        if (connector != null) {
-            log("Registering in-process network stack connector");
-            registerNetworkStackService(connector);
-            return;
-        }
-        // Start the network stack process. The service will be added to the service manager in
-        // NetworkStackConnection.onServiceConnected().
-        log("Starting network stack process");
-        final Intent intent = new Intent(INetworkStackConnector.class.getName());
-        final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
-        intent.setComponent(comp);
-
-        if (comp == null) {
-            logWtf("Could not resolve the network stack with " + intent, null);
+        if (intent == null) {
+            logWtf("Could not resolve the network stack", null);
             // TODO: crash/reboot system server ?
             return;
         }
-        final PackageManager pm = context.getPackageManager();
+
+        // Start the network stack. The service will be added to the service manager in
+        // NetworkStackConnection.onServiceConnected().
+        if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+            logWtf("Could not bind to network stack with " + intent, null);
+            return;
+            // TODO: crash/reboot system server if no network stack after a timeout ?
+        }
+
+        log("Network stack service start requested");
+    }
+
+    @Nullable
+    private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) {
+        final String baseAction = INetworkStackConnector.class.getName();
+        final Intent intent =
+                new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction);
+        final ComponentName comp = intent.resolveSystemService(pm, 0);
+
+        if (comp == null) {
+            return null;
+        }
+        intent.setComponent(comp);
+
         int uid = -1;
         try {
             uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
@@ -218,25 +226,27 @@
             logWtf("Network stack package not found", e);
             // Fall through
         }
-        if (uid != Process.NETWORK_STACK_UID) {
+
+        final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
+        if (uid != expectedUid) {
             throw new SecurityException("Invalid network stack UID: " + uid);
         }
 
+        if (!inSystemProcess) {
+            checkNetworkStackPermission(pm, comp);
+        }
+
+        return intent;
+    }
+
+    private void checkNetworkStackPermission(
+            @NonNull PackageManager pm, @NonNull ComponentName comp) {
         final int hasPermission =
                 pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
         if (hasPermission != PERMISSION_GRANTED) {
             throw new SecurityException(
                     "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
         }
-
-        if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
-                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
-            logWtf("Could not bind to network stack in-process, or in app with " + intent, null);
-            return;
-            // TODO: crash/reboot system server if no network stack after a timeout ?
-        }
-
-        log("Network stack service start requested");
     }
 
     private void log(@NonNull String message) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 4293247..039a4b7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -29,6 +29,7 @@
 import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
 import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
 
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
 import static org.mockito.Matchers.any;
@@ -4157,8 +4158,9 @@
         final byte[] token = new byte[32];
         final long handle = 123456;
         final String password = "password";
-        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM)))
-            .thenReturn(handle);
+        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
+                nullable(EscrowTokenStateChangeCallback.class)))
+                .thenReturn(handle);
         assertTrue(dpm.setResetPasswordToken(admin1, token));
 
         // test password activation
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index d343ac1..77515258 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -338,7 +338,7 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
@@ -367,7 +367,7 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -393,7 +393,7 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
-        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -417,7 +417,7 @@
             throws RemoteException {
         final String token = "some-high-entropy-secure-token";
         enableSyntheticPassword();
-        long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -427,7 +427,7 @@
             throws RemoteException {
         final String token = "some-high-entropy-secure-token";
         initializeCredentialUnderSP(null, PRIMARY_USER_ID);
-        long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -443,7 +443,7 @@
                 PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
         enableSyntheticPassword();
 
-        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         // Token not activated immediately since user password exists
         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
         // Activate token (password gets migrated to SP at the same time)
@@ -461,7 +461,7 @@
 
         mHasSecureLockScreen = false;
         enableSyntheticPassword();
-        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+        long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
         try {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 3ebc6ad..e9edba5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -185,6 +185,18 @@
     }
 
     @MediumTest
+    public void testRemoveUserByHandle_ThrowsException() {
+        synchronized (mUserRemoveLock) {
+            try {
+                mUserManager.removeUser(null);
+                fail("Expected IllegalArgumentException on passing in a null UserHandle.");
+            } catch (IllegalArgumentException expected) {
+                // Do nothing - exception is expected.
+            }
+        }
+    }
+
+    @MediumTest
     public void testAddGuest() throws Exception {
         UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
         UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
@@ -520,6 +532,12 @@
         }
     }
 
+    public void testGetUserSwitchability() {
+        int userSwitchable = mUserManager.getUserSwitchability();
+        assertEquals("Expected users to be switchable", UserManager.SWITCHABILITY_STATUS_OK,
+                userSwitchable);
+    }
+
     @LargeTest
     public void testSwitchUser() {
         ActivityManager am = getContext().getSystemService(ActivityManager.class);
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 d202e16..032eba1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -270,7 +270,7 @@
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
         return createTestAppWindowToken(dc, windowingMode, activityType,
-                true /*skipOnParentChanged */);
+                false /*skipOnParentChanged */);
     }
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2907021..2fc6efa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -74,7 +74,7 @@
         public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
             mRelativeLayersForControl.remove(sc);
             mLayersForControl.put(sc, layer);
-            return super.setLayer(sc, layer);
+            return this;
         }
 
         @Override
@@ -83,7 +83,7 @@
                 int layer) {
             mRelativeLayersForControl.put(sc, relativeTo);
             mLayersForControl.put(sc, layer);
-            return super.setRelativeLayer(sc, relativeTo, layer);
+            return this;
         }
 
         private int getLayer(SurfaceControl sc) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b9a5676..9498e16 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -17,6 +17,7 @@
 package com.android.server.usage;
 
 import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
+import static android.app.usage.UsageEvents.Event.DEVICE_STARTUP;
 import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
 import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
 import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -137,15 +138,18 @@
 
         // During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
         // is last time UsageStatsDatabase is persisted to disk.
+        // Also add a DEVICE_STARTUP event with current system timestamp.
         final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
         if (currentDailyStats != null) {
-            final int size = currentDailyStats.events.size();
-            if (size == 0 || currentDailyStats.events.get(size - 1).mEventType != DEVICE_SHUTDOWN) {
-                // The last event in event list is not DEVICE_SHUTDOWN, then we insert one.
-                final Event event = new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved);
-                event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
-                currentDailyStats.addEvent(event);
-            }
+            // File system timestamp only has precision of 1 second, add 1000ms to make up
+            // for the loss of round up.
+            final Event shutdownEvent =
+                    new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved + 1000);
+            shutdownEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
+            currentDailyStats.addEvent(shutdownEvent);
+            final Event startupEvent = new Event(DEVICE_STARTUP, currentTimeMillis);
+            startupEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
+            currentDailyStats.addEvent(startupEvent);
         }
 
         if (mDatabase.isNewUpdate()) {
@@ -956,6 +960,8 @@
                 return "KEYGUARD_HIDDEN";
             case Event.DEVICE_SHUTDOWN:
                 return "DEVICE_SHUTDOWN";
+            case Event.DEVICE_STARTUP:
+                return "DEVICE_STARTUP";
             default:
                 return "UNKNOWN_TYPE_" + eventType;
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b9440eb..ad1e3ef 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1389,6 +1389,16 @@
                         resetCurAssistant(userHandle);
                         initForUser(userHandle);
                         switchImplementationIfNeededLocked(true);
+
+                        Context context = getContext();
+                        context.getSystemService(RoleManager.class).clearRoleHoldersAsUser(
+                                RoleManager.ROLE_ASSISTANT, 0, UserHandle.of(userHandle),
+                                context.getMainExecutor(), successful -> {
+                                    if (!successful) {
+                                        Slog.e(TAG,
+                                                "Failed to clear default assistant for force stop");
+                                    }
+                                });
                     }
                 } else if (hitRec && doit) {
                     // We are just force-stopping the current recognizer, which is not
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index e43b2b7..5b806a6 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -16,7 +16,6 @@
 
 import android.app.ActivityManager;
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -34,9 +33,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
 
 /**
  * Class for managing the default dialer application that will receive incoming calls, and be
@@ -75,11 +76,18 @@
             int user) {
         long identity = Binder.clearCallingIdentity();
         try {
-            RoleManagerCallback.Future cb = new RoleManagerCallback.Future();
+            CompletableFuture<Void> future = new CompletableFuture<>();
+            Consumer<Boolean> callback = successful -> {
+                if (successful) {
+                    future.complete(null);
+                } else {
+                    future.completeExceptionally(new RuntimeException());
+                }
+            };
             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
                     RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(user),
-                    AsyncTask.THREAD_POOL_EXECUTOR, cb);
-            cb.get(5, TimeUnit.SECONDS);
+                    AsyncTask.THREAD_POOL_EXECUTOR, callback);
+            future.get(5, TimeUnit.SECONDS);
             return true;
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             Slog.e(TAG, "Failed to set default dialer to " + packageName + " for user " + user, e);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7688ac6..52c5425 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -25,7 +25,6 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
-import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -478,12 +477,6 @@
             "android.telecom.extra.START_CALL_WITH_RTT";
 
     /**
-     * A boolean extra set to indicate whether an app is eligible to be bound to when there are
-     * ongoing calls on the device.
-     */
-    public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
-
-    /**
      * A boolean meta-data value indicating whether an {@link InCallService} implements an
      * in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
      * would also like to replace the in-call interface should set this meta-data to {@code true} in
@@ -1221,8 +1214,8 @@
      *
      * @hide
      * @deprecated Use
-     * {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, UserHandle, Executor,
-     * RoleManagerCallback)} instead.
+     * {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, UserHandle,
+     * Executor, java.util.function.Consumer)} instead.
      */
     @SystemApi
     @Deprecated
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
old mode 100644
new mode 100755
index 5262cf8..d79a168
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2653,6 +2653,18 @@
      */
     public static final String KEY_USE_USIM_BOOL = "use_usim_bool";
 
+    /**
+     * Determines whether the carrier wants to cancel the cs reject notification automatically
+     * when the voice registration state changes.
+     * If true, the notification will be automatically removed
+     *          when the voice registration state changes.
+     * If false, the notification will persist until the user dismisses it,
+     *           the SIM is removed, or the device is rebooted.
+     * @hide
+     */
+    public static final String KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION =
+            "carrier_auto_cancel_cs_notification";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -3039,6 +3051,7 @@
                 });
         sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
+        sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 3dea6f4..0aeb0f6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -151,6 +151,17 @@
     }
 
     /**
+     * Return the Received Signal Strength Indicator
+     *
+     * @return the RSSI in dBm (-113, -51) or
+     *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE}.
+     * @hide
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
      * Return the Bit Error Rate
      *
      * @return the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4dcb410..549c044 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -25,12 +25,11 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.CountryDetector;
 import android.net.Uri;
-import android.os.SystemProperties;
 import android.os.PersistableBundle;
+import android.os.SystemProperties;
 import android.provider.Contacts;
 import android.provider.ContactsContract;
 import android.telecom.PhoneAccount;
@@ -1738,7 +1737,7 @@
      * @return true if the number is in the list of emergency numbers
      *         listed in the RIL / SIM, otherwise return false.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} instead.
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} instead.
      */
     @Deprecated
     public static boolean isEmergencyNumber(String number) {
@@ -1754,7 +1753,7 @@
      * @return true if the number is in the list of emergency numbers
      *         listed in the RIL / SIM, otherwise return false.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1785,7 +1784,7 @@
      *         listed in the RIL / SIM, *or* if the number starts with the
      *         same digits as any of those emergency numbers.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1814,7 +1813,7 @@
      *         listed in the RIL / SIM, *or* if the number starts with the
      *         same digits as any of those emergency numbers.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1883,7 +1882,7 @@
      * @return if the number is an emergency number for the specific country, then return true,
      * otherwise false
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1903,7 +1902,7 @@
      * @return if the number is an emergency number for the specific country, then return true,
      * otherwise false
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1934,7 +1933,7 @@
      *         country, *or* if the number starts with the same digits as
      *         any of those emergency numbers.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -1964,7 +1963,7 @@
      *         country, *or* if the number starts with the same digits as
      *         any of those emergency numbers.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -2017,7 +2016,7 @@
     private static boolean isEmergencyNumberInternal(int subId, String number,
                                                      String defaultCountryIso,
                                                      boolean useExactMatch) {
-        return TelephonyManager.getDefault().isCurrentEmergencyNumber(number);
+        return TelephonyManager.getDefault().isEmergencyNumber(number);
     }
 
     /**
@@ -2028,7 +2027,7 @@
      * @return true if the specified number is an emergency number for the country the user
      * is currently in.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
      *             instead.
      */
     @Deprecated
@@ -2045,7 +2044,7 @@
      * @return true if the specified number is an emergency number for the country the user
      * is currently in.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -2079,7 +2078,7 @@
      *
      * @see android.location.CountryDetector
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
@@ -2110,7 +2109,7 @@
      * @return true if the specified number is an emergency number for a local country, based on the
      *              CountryDetector.
      *
-     * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+     * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
      *             instead.
      *
      * @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9ca5717..16dafd6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -96,6 +96,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -10030,18 +10031,21 @@
      * a SecurityException if the caller does not have the permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @Nullable
-    public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
+    @NonNull
+    public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList() {
+        Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) {
-                return null;
+            if (telephony != null) {
+                return telephony.getEmergencyNumberList(mContext.getOpPackageName());
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
-            return telephony.getCurrentEmergencyNumberList(mContext.getOpPackageName());
         } catch (RemoteException ex) {
-            Log.e(TAG, "getCurrentEmergencyNumberList RemoteException", ex);
+            Log.e(TAG, "getEmergencyNumberList RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
-        return null;
+        return emergencyNumberList;
     }
 
     /**
@@ -10080,31 +10084,34 @@
      * a SecurityException if the caller does not have the permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @Nullable
-    public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList(
+    @NonNull
+    public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
             @EmergencyServiceCategories int categories) {
+        Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) {
-                return null;
-            }
-            Map<Integer, List<EmergencyNumber>> numberMap = telephony
-                    .getCurrentEmergencyNumberList(mContext.getOpPackageName());
-            if (numberMap != null) {
-                for (Integer subscriptionId : numberMap.keySet()) {
-                    List<EmergencyNumber> numberList = numberMap.get(subscriptionId);
-                    for (EmergencyNumber number : numberList) {
-                        if (!number.isInEmergencyServiceCategories(categories)) {
-                            numberList.remove(number);
+            if (telephony != null) {
+                emergencyNumberList = telephony.getEmergencyNumberList(
+                        mContext.getOpPackageName());
+                if (emergencyNumberList != null) {
+                    for (Integer subscriptionId : emergencyNumberList.keySet()) {
+                        List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
+                        for (EmergencyNumber number : numberList) {
+                            if (!number.isInEmergencyServiceCategories(categories)) {
+                                numberList.remove(number);
+                            }
                         }
                     }
                 }
+                return emergencyNumberList;
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
-            return numberMap;
         } catch (RemoteException ex) {
-            Log.e(TAG, "getCurrentEmergencyNumberList with Categories RemoteException", ex);
+            Log.e(TAG, "getEmergencyNumberList with Categories RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
-        return null;
+        return emergencyNumberList;
     }
 
     /**
@@ -10118,15 +10125,17 @@
      * @return {@code true} if the given number is an emergency number based on current locale,
      * sim, modem and network; {@code false} otherwise.
      */
-    public boolean isCurrentEmergencyNumber(@NonNull String number) {
+    public boolean isEmergencyNumber(@NonNull String number) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) {
-                return false;
+            if (telephony != null) {
+                return telephony.isEmergencyNumber(number, true);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
-            return telephony.isCurrentEmergencyNumber(number, true);
         } catch (RemoteException ex) {
-            Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
+            Log.e(TAG, "isEmergencyNumber RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
         return false;
     }
@@ -10155,15 +10164,17 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isCurrentPotentialEmergencyNumber(@NonNull String number) {
+    public boolean isPotentialEmergencyNumber(@NonNull String number) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony == null) {
-                return false;
+            if (telephony != null) {
+                return telephony.isEmergencyNumber(number, false);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
-            return telephony.isCurrentEmergencyNumber(number, false);
         } catch (RemoteException ex) {
-            Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
+            Log.e(TAG, "isEmergencyNumber RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
         return false;
     }
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 332aae1..bcb47f7 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -243,7 +243,6 @@
      */
     public boolean isPreferred() { return  mPreferred; }
 
-    /** @hide */
     @Override
     public int describeContents() {
         return 0;
@@ -266,7 +265,6 @@
         return (o == this || toString().equals(o.toString()));
     }
 
-    /** @hide */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mProfileId);
@@ -288,7 +286,6 @@
         dest.writeBoolean(mPreferred);
     }
 
-    /** @hide */
     public static final @android.annotation.NonNull Parcelable.Creator<DataProfile> CREATOR =
             new Parcelable.Creator<DataProfile>() {
         @Override
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 5373c38..173f4ed 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -302,7 +302,7 @@
      *
      * @return the dialing number.
      */
-    public String getNumber() {
+    public @NonNull String getNumber() {
         return mNumber;
     }
 
@@ -311,7 +311,7 @@
      *
      * @return the country code string (lowercase character) in ISO 3166 format.
      */
-    public String getCountryIso() {
+    public @NonNull String getCountryIso() {
         return mCountryIso;
     }
 
@@ -320,7 +320,7 @@
      *
      * @return the Mobile Network Code of the emergency number.
      */
-    public String getMnc() {
+    public @NonNull String getMnc() {
         return mMnc;
     }
 
@@ -328,6 +328,8 @@
      * Returns the bitmask of emergency service categories of the emergency number.
      *
      * @return bitmask of the emergency service categories
+     *
+     * @hide
      */
     public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
         return mEmergencyServiceCategoryBitmask;
@@ -357,7 +359,7 @@
      *
      * @return a list of the emergency service categories
      */
-    public List<Integer> getEmergencyServiceCategories() {
+    public @NonNull List<Integer> getEmergencyServiceCategories() {
         List<Integer> categories = new ArrayList<>();
         if (serviceUnspecified()) {
             categories.add(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED);
@@ -384,7 +386,7 @@
      *         number does not have a specified emergency Uniform Resource Name.
      */
     public @NonNull List<String> getEmergencyUrns() {
-        return mEmergencyUrns;
+        return Collections.unmodifiableList(mEmergencyUrns);
     }
 
     /**
@@ -421,6 +423,8 @@
      * Returns the bitmask of the sources of the emergency number.
      *
      * @return bitmask of the emergency number sources
+     *
+     * @hide
      */
     public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
         return mEmergencyNumberSourceBitmask;
@@ -431,7 +435,7 @@
      *
      * @return a list of emergency number sources
      */
-    public List<Integer> getEmergencyNumberSources() {
+    public @NonNull List<Integer> getEmergencyNumberSources() {
         List<Integer> sources = new ArrayList<>();
         for (Integer source : EMERGENCY_NUMBER_SOURCE_SET) {
             if ((mEmergencyNumberSourceBitmask & source) == source) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 793ac3c..751ce9d 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
@@ -842,7 +843,7 @@
      *            3gpp 22.101, Section 10 - Emergency Calls.
      */
     @VisibleForTesting
-    public void setEmergencyUrns(List<String> emergencyUrns) {
+    public void setEmergencyUrns(@NonNull List<String> emergencyUrns) {
         mEmergencyUrns = emergencyUrns;
     }
 
@@ -916,7 +917,7 @@
      * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
      *            3gpp 22.101, Section 10 - Emergency Calls.
      */
-    public List<String> getEmergencyUrns() {
+    public @NonNull List<String> getEmergencyUrns() {
         return mEmergencyUrns;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c6fa22b..122747a65 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1773,12 +1773,12 @@
     /**
      * Return the emergency number list from all the active subscriptions.
      */
-    Map getCurrentEmergencyNumberList(String callingPackage);
+    Map getEmergencyNumberList(String callingPackage);
 
     /**
      * Identify if the number is emergency number, based on all the active subscriptions.
      */
-    boolean isCurrentEmergencyNumber(String number, boolean exactMatch);
+    boolean isEmergencyNumber(String number, boolean exactMatch);
 
     /**
      * Return a list of certs in hex string from loaded carrier privileges access rules.
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 7478a00..ef7c605 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -19,7 +19,6 @@
 import android.Manifest.permission;
 import android.app.AppOpsManager;
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -51,9 +50,11 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
 
 /**
  * Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -634,12 +635,19 @@
             }
 
             // Update the setting.
-            RoleManagerCallback.Future res = new RoleManagerCallback.Future();
+            CompletableFuture<Void> future = new CompletableFuture<>();
+            Consumer<Boolean> callback = successful -> {
+                if (successful) {
+                    future.complete(null);
+                } else {
+                    future.completeExceptionally(new RuntimeException());
+                }
+            };
             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
                     RoleManager.ROLE_SMS, applicationData.mPackageName, 0, UserHandle.of(userId),
-                    AsyncTask.THREAD_POOL_EXECUTOR, res);
+                    AsyncTask.THREAD_POOL_EXECUTOR, callback);
             try {
-                res.get(5, TimeUnit.SECONDS);
+                future.get(5, TimeUnit.SECONDS);
             } catch (InterruptedException | ExecutionException | TimeoutException e) {
                 Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
                 return;
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index ed8a533..a03fae0 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -165,9 +165,7 @@
         PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
         PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                 PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        if (enableRollback) {
-            params.setEnableRollback();
-        }
+        params.setEnableRollback(enableRollback);
         int sessionId = packageInstaller.createSession(params);
         session = packageInstaller.openSession(sessionId);
 
@@ -224,11 +222,9 @@
         if (staged) {
             multiPackageParams.setStaged();
         }
-        if (enableRollback) {
-            // TODO: Do we set this on the parent params, the child params, or
-            // both?
-            multiPackageParams.setEnableRollback();
-        }
+        // TODO: Do we set this on the parent params, the child params, or
+        // both?
+        multiPackageParams.setEnableRollback(enableRollback);
         int multiPackageId = packageInstaller.createSession(multiPackageParams);
         PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
 
@@ -242,9 +238,7 @@
             if (resourceName.endsWith(".apex")) {
                 params.setInstallAsApex();
             }
-            if (enableRollback) {
-                params.setEnableRollback();
-            }
+            params.setEnableRollback(enableRollback);
             int sessionId = packageInstaller.createSession(params);
             session = packageInstaller.openSession(sessionId);
 
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 251ca0c..5336141 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -183,11 +183,11 @@
   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
 
   // Preserve non-ASCII whitespace including extended ASCII characters
-  EXPECT_TRUE(TestParse(R"(<string name="foo3">&#160;Hello&#160;</string>)"));
+  EXPECT_TRUE(TestParse(R"(<string name="foo3">&#160;Hello&#x202F;World&#160;</string>)"));
 
   str = test::GetValue<String>(&table_, "string/foo3");
   ASSERT_THAT(str, NotNull());
-  EXPECT_THAT(*str->value, StrEq("\xC2\xA0Hello\xC2\xA0"));
+  EXPECT_THAT(*str->value, StrEq("\xC2\xA0Hello\xE2\x80\xAFWorld\xC2\xA0"));
   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
 
   EXPECT_TRUE(TestParse(R"(<string name="foo4">2005年6月1日</string>)"));
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index f0e4d9e..a571aee 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -40,8 +40,6 @@
 namespace aapt {
 namespace ResourceUtils {
 
-constexpr int32_t kNonBreakingSpace = 0xa0;
-
 Maybe<ResourceName> ToResourceName(
     const android::ResTable::resource_name& name_in) {
   // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
@@ -854,7 +852,8 @@
   Utf8Iterator iter(text);
   while (iter.HasNext()) {
     char32_t codepoint = iter.Next();
-    if (!preserve_spaces_ && !quote_ && codepoint != kNonBreakingSpace && iswspace(codepoint)) {
+    if (!preserve_spaces_ && !quote_ && (codepoint <= std::numeric_limits<char>::max())
+                                         && isspace(static_cast<char>(codepoint))) {
       if (!last_codepoint_was_space_) {
         // Emit a space if it's the first.
         xml_string_.text += ' ';
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 44d88bb..6f6c1aa 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -97,7 +97,7 @@
     /**
      * The suffix of the generated class name after the class's binary name.
      */
-    private static final String GENERATED_CLASS_SUFFIX = "$$InspectionCompanion";
+    private static final String GENERATED_CLASS_SUFFIX = "$InspectionCompanion";
 
     /**
      * The null resource ID, copied to avoid a host dependency on platform code.
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index 01d9430..fd142c6 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -34,6 +34,7 @@
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
 
 
 /**
@@ -127,13 +128,38 @@
 
             final InspectableClassModel model = modelMap.computeIfAbsent(
                     classElement.get().getQualifiedName().toString(),
-                    k -> new InspectableClassModel(ClassName.get(classElement.get())));
+                    k -> {
+                        if (hasNestedInspectionCompanion(classElement.get())) {
+                            fail(
+                                    String.format(
+                                            "Class %s already has an inspection companion.",
+                                            classElement.get().getQualifiedName().toString()),
+                                    element);
+                        }
+                        return new InspectableClassModel(ClassName.get(classElement.get()));
+                    });
 
             processor.process(element, model);
         }
     }
 
     /**
+     * Determine if a class has a nested class named {@code InspectionCompanion}.
+     *
+     * @param typeElement A type element representing the class to check
+     * @return f the class contains a class named {@code InspectionCompanion}
+     */
+    private static boolean hasNestedInspectionCompanion(TypeElement typeElement) {
+        for (TypeElement nestedClass : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
+            if (nestedClass.getSimpleName().toString().equals("InspectionCompanion")) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Get the nearest enclosing class if there is one.
      *
      * If {@param element} represents a class, it will be returned wrapped in an optional.
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
index a44c43e..9a0fe5b 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
@@ -12,7 +12,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
index 764aa8b..b491de1 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -13,7 +13,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
index 75f2813..7d18058 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -12,7 +12,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index 0cac462..dc27abb 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -11,7 +11,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class Outer$Inner$$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
+public final class Outer$Inner$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index ce0f867..738bcd3 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -11,7 +11,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
index f7357fe..82dd66e 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
@@ -12,7 +12,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 556d8dd..08ea696 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -12,7 +12,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index d72cdd5..3bfa78a 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -11,7 +11,7 @@
  * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
  * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
  */
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index ee60408..0b55794 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -539,9 +539,10 @@
         mFqdn = fqdn;
     }
 
-    /** {@hide} */
-    @SystemApi
-    public @Nullable String getFqdn() {
+    /**
+     * Returns the Fully Qualified Domain Name of the network if it is a Passpoint network.
+     */
+    public @Nullable String getPasspointFqdn() {
         return mFqdn;
     }
 
@@ -550,9 +551,10 @@
         mProviderFriendlyName = providerFriendlyName;
     }
 
-    /** {@hide} */
-    @SystemApi
-    public @Nullable String getProviderFriendlyName() {
+    /**
+     * Returns the Provider Friendly Name of the network if it is a Passpoint network.
+     */
+    public @Nullable String getPasspointProviderFriendlyName() {
         return mProviderFriendlyName;
     }
 
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index a47e70b..d97f6fb 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -36,7 +36,7 @@
  * <ul>
  *      <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
  *      <li>Creating a network-specifier when requesting a Aware connection using
- *      {@link WifiAwareManager.NetworkSpecifierBuilder}.
+ *      {@link WifiAwareNetworkSpecifier.Builder}.
  * </ul>
  * <p>
  * The {@link #close()} method must be called to destroy discovery sessions once they are
@@ -270,7 +270,7 @@
      * <p>
      * To set up an encrypted link use the
      * {@link #createNetworkSpecifierPassphrase(PeerHandle, String)} API.
-     * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+     * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
      *
      * @param peerHandle The peer's handle obtained through
      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
@@ -320,7 +320,7 @@
      * <p>
      * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
      * and a Publisher is a RESPONDER.
-     * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+     * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
      *
      * @param peerHandle The peer's handle obtained through
      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
@@ -380,7 +380,7 @@
      * <p>
      * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
      * and a Publisher is a RESPONDER.
-     * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+     * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
      *
      * @param peerHandle The peer's handle obtained through
      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
diff --git a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
index ce67abf..ca473db 100644
--- a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.aware;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -29,7 +30,7 @@
      *
      * @param peerHandle The {@link PeerHandle} to be made parcelable.
      */
-    public ParcelablePeerHandle(PeerHandle peerHandle) {
+    public ParcelablePeerHandle(@NonNull PeerHandle peerHandle) {
         super(peerHandle.peerId);
     }
 
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 1a5cd5a..c9b0b12 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -35,7 +34,6 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
-import android.text.TextUtils;
 import android.util.Log;
 
 import libcore.util.HexEncoding;
@@ -59,7 +57,7 @@
  * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
  * <li>Create a Aware network specifier to be used with
  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
- * to set-up a Aware connection with a peer. Refer to {@link NetworkSpecifierBuilder}.
+ * to set-up a Aware connection with a peer. Refer to {@link WifiAwareNetworkSpecifier.Builder}.
  * </ul>
  * <p>
  *     Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that
@@ -108,7 +106,7 @@
  *        <li>{@link NetworkRequest.Builder#addTransportType(int)} of
  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
- *        {@link NetworkSpecifierBuilder}.
+ *        {@link WifiAwareNetworkSpecifier.Builder}.
  *    </ul>
  */
 @SystemService(Context.WIFI_AWARE_SERVICE)
@@ -408,7 +406,7 @@
 
         if (!WifiAwareUtils.isLegacyVersion(mContext, Build.VERSION_CODES.Q)) {
             throw new UnsupportedOperationException(
-                    "API not deprecated - use WifiAwareManager.NetworkSpecifierBuilder");
+                    "API not deprecated - use WifiAwareNetworkSpecifier.Builder");
         }
 
         if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
@@ -813,198 +811,4 @@
             mOriginalCallback.onSessionTerminated();
         }
     }
-
-    /**
-     * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
-     * peer.
-     * <p>
-     * Note that all Wi-Fi Aware connection specifier objects must call the
-     * {@link NetworkSpecifierBuilder#setDiscoverySession(DiscoverySession)} to specify the context
-     * within which the connection is created, and
-     * {@link NetworkSpecifierBuilder#setPeerHandle(PeerHandle)} to specify the peer to which the
-     * connection is created.
-     */
-    public static final class NetworkSpecifierBuilder {
-        private DiscoverySession mDiscoverySession;
-        private PeerHandle mPeerHandle;
-        private String mPskPassphrase;
-        private byte[] mPmk;
-        private int mPort = 0; // invalid value
-        private int mTransportProtocol = -1; // invalid value
-
-        /**
-         * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
-         * discovery session in whose context the connection is created.
-         * <p>
-         * Note: this method must be called for any connection request!
-         *
-         * @param discoverySession A Wi-Fi Aware discovery session.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull NetworkSpecifierBuilder setDiscoverySession(
-                @NonNull DiscoverySession discoverySession) {
-            if (discoverySession == null) {
-                throw new IllegalArgumentException("Non-null discoverySession required");
-            }
-            mDiscoverySession = discoverySession;
-            return this;
-        }
-
-        /**
-         * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
-         * requested. The peer is discovered through Wi-Fi Aware discovery,
-         * <p>
-         * Note: this method must be called for any connection request!
-         *
-         * @param peerHandle The peer's handle obtained through
-         * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
-         *                   or
-         *                   {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull NetworkSpecifierBuilder setPeerHandle(@NonNull PeerHandle peerHandle) {
-            if (peerHandle == null) {
-                throw new IllegalArgumentException("Non-null peerHandle required");
-            }
-            mPeerHandle = peerHandle;
-            return this;
-        }
-
-        /**
-         * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
-         * is optional - if not called, then an Open (unencrypted) connection will be created.
-         *
-         * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull NetworkSpecifierBuilder setPskPassphrase(@NonNull String pskPassphrase) {
-            if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
-                throw new IllegalArgumentException("Passphrase must meet length requirements");
-            }
-            mPskPassphrase = pskPassphrase;
-            return this;
-        }
-
-        /**
-         * Configure the PMK for the Wi-Fi Aware connection being requested. This method
-         * is optional - if not called, then an Open (unencrypted) connection will be created.
-         *
-         * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
-         *            encrypting the data-path. Use the {@link #setPskPassphrase(String)} to
-         *            specify a Passphrase.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         * @hide
-         */
-        @SystemApi
-        public @NonNull NetworkSpecifierBuilder setPmk(@NonNull byte[] pmk) {
-            if (!WifiAwareUtils.validatePmk(pmk)) {
-                throw new IllegalArgumentException("PMK must 32 bytes");
-            }
-            mPmk = pmk;
-            return this;
-        }
-
-        /**
-         * Configure the port number which will be used to create a connection over this link. This
-         * configuration should only be done on the server device, e.g. the device creating the
-         * {@link java.net.ServerSocket}.
-         * <p>Notes:
-         * <ul>
-         *     <li>The server device must be the Publisher device!
-         *     <li>The port information can only be specified on secure links, specified using
-         *     {@link #setPskPassphrase(String)}.
-         * </ul>
-         *
-         * @param port A positive integer indicating the port to be used for communication.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull NetworkSpecifierBuilder setPort(int port) {
-            if (port <= 0 || port > 65535) {
-                throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
-            }
-            mPort = port;
-            return this;
-        }
-
-        /**
-         * Configure the transport protocol which will be used to create a connection over this
-         * link. This configuration should only be done on the server device, e.g. the device
-         * creating the {@link java.net.ServerSocket} for TCP.
-         * <p>Notes:
-         * <ul>
-         *     <li>The server device must be the Publisher device!
-         *     <li>The transport protocol information can only be specified on secure links,
-         *     specified using {@link #setPskPassphrase(String)}.
-         * </ul>
-         * The transport protocol number is assigned by the Internet Assigned Numbers Authority
-         * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
-         *
-         * @param transportProtocol The transport protocol to be used for communication.
-         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull NetworkSpecifierBuilder setTransportProtocol(int transportProtocol) {
-            if (transportProtocol < 0 || transportProtocol > 255) {
-                throw new IllegalArgumentException(
-                        "The transport protocol must be in range [0, 255]");
-            }
-            mTransportProtocol = transportProtocol;
-            return this;
-        }
-
-        /**
-         * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)}
-         * for a WiFi Aware connection (link) to the specified peer. The
-         * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
-         * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
-         * <p> The default builder constructor will initialize a NetworkSpecifier which requests an
-         * open (non-encrypted) link. To request an encrypted link use the
-         * {@link #setPskPassphrase(String)} builder method.
-         *
-         * @return A {@link NetworkSpecifier} to be used to construct
-         * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
-         * to {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
-         * android.net.ConnectivityManager.NetworkCallback)}
-         * [or other varieties of that API].
-         */
-        public @NonNull NetworkSpecifier build() {
-            if (mDiscoverySession == null) {
-                throw new IllegalStateException("Null discovery session!?");
-            }
-            if (mPskPassphrase != null & mPmk != null) {
-                throw new IllegalStateException(
-                        "Can only specify a Passphrase or a PMK - not both!");
-            }
-
-            int role = mDiscoverySession instanceof SubscribeDiscoverySession
-                    ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
-                    : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
-
-            if (mPort != 0 || mTransportProtocol != -1) {
-                if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
-                    throw new IllegalStateException(
-                            "Port and transport protocol information can only "
-                                    + "be specified on the Publisher device (which is the server");
-                }
-                if (TextUtils.isEmpty(mPskPassphrase) && mPmk == null) {
-                    throw new IllegalStateException("Port and transport protocol information can "
-                            + "only be specified on a secure link");
-                }
-            }
-
-            if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
-                throw new IllegalStateException("Null peerHandle!?");
-            }
-
-            return new WifiAwareNetworkSpecifier(
-                    WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
-                    mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
-                    null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
-        }
-    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index 020cb56..fd26817b 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -75,7 +75,7 @@
     /**
      * Get the port number to be used to create a network connection to the Wi-Fi Aware peer.
      * The port information is provided by the app running on the peer which requested the
-     * connection, using the {@link WifiAwareManager.NetworkSpecifierBuilder#setPort(int)}.
+     * connection, using the {@link WifiAwareNetworkSpecifier.Builder#setPort(int)}.
      *
      * @return A port number on the peer. A value of 0 indicates that no port was specified by the
      *         peer.
@@ -88,7 +88,7 @@
      * Get the transport protocol to be used to communicate over a network connection to the Wi-Fi
      * Aware peer. The transport protocol is provided by the app running on the peer which requested
      * the connection, using the
-     * {@link WifiAwareManager.NetworkSpecifierBuilder#setTransportProtocol(int)}.
+     * {@link WifiAwareNetworkSpecifier.Builder#setTransportProtocol(int)}.
      * <p>
      * The transport protocol number is assigned by the Internet Assigned Numbers Authority
      * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 59f534a..b225116 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -16,9 +16,15 @@
 
 package android.net.wifi.aware;
 
+import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.net.NetworkSpecifier;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
+import android.text.TextUtils;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -29,8 +35,6 @@
  * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or
  * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase)
  * versions.
- *
- * @hide
  */
 public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
     /**
@@ -138,6 +142,8 @@
      * device they all get the same link. However, the link is only set up on the first request -
      * hence only the first can transmit the port information. But we don't want to expose that
      * information to other apps. Limiting to secure links would (usually) imply single app usage.
+     *
+     * @hide
      */
     public final int transportProtocol;
 
@@ -292,4 +298,197 @@
             throw new SecurityException("mismatched UIDs");
         }
     }
+
+    /**
+     * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
+     * peer.
+     * <p>
+     * Note that all Wi-Fi Aware connection specifier objects must call the
+     * {@link Builder#setDiscoverySession(DiscoverySession)} to specify the context
+     * within which the connection is created, and
+     * {@link Builder#setPeerHandle(PeerHandle)} to specify the peer to which the
+     * connection is created.
+     */
+    public static final class Builder {
+        private DiscoverySession mDiscoverySession;
+        private PeerHandle mPeerHandle;
+        private String mPskPassphrase;
+        private byte[] mPmk;
+        private int mPort = 0; // invalid value
+        private int mTransportProtocol = -1; // invalid value
+
+        /**
+         * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
+         * discovery session in whose context the connection is created.
+         * <p>
+         * Note: this method must be called for any connection request!
+         *
+         * @param discoverySession A Wi-Fi Aware discovery session.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull Builder setDiscoverySession(@NonNull DiscoverySession discoverySession) {
+            if (discoverySession == null) {
+                throw new IllegalArgumentException("Non-null discoverySession required");
+            }
+            mDiscoverySession = discoverySession;
+            return this;
+        }
+
+        /**
+         * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
+         * requested. The peer is discovered through Wi-Fi Aware discovery,
+         * <p>
+         * Note: this method must be called for any connection request!
+         *
+         * @param peerHandle The peer's handle obtained through
+         * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+         *                   or
+         *                   {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull Builder setPeerHandle(@NonNull PeerHandle peerHandle) {
+            if (peerHandle == null) {
+                throw new IllegalArgumentException("Non-null peerHandle required");
+            }
+            mPeerHandle = peerHandle;
+            return this;
+        }
+
+        /**
+         * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
+         * is optional - if not called, then an Open (unencrypted) connection will be created.
+         *
+         * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull Builder setPskPassphrase(@NonNull String pskPassphrase) {
+            if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
+                throw new IllegalArgumentException("Passphrase must meet length requirements");
+            }
+            mPskPassphrase = pskPassphrase;
+            return this;
+        }
+
+        /**
+         * Configure the PMK for the Wi-Fi Aware connection being requested. This method
+         * is optional - if not called, then an Open (unencrypted) connection will be created.
+         *
+         * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+         *            encrypting the data-path. Use the {@link #setPskPassphrase(String)} to
+         *            specify a Passphrase.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setPmk(@NonNull byte[] pmk) {
+            if (!WifiAwareUtils.validatePmk(pmk)) {
+                throw new IllegalArgumentException("PMK must 32 bytes");
+            }
+            mPmk = pmk;
+            return this;
+        }
+
+        /**
+         * Configure the port number which will be used to create a connection over this link. This
+         * configuration should only be done on the server device, e.g. the device creating the
+         * {@link java.net.ServerSocket}.
+         * <p>Notes:
+         * <ul>
+         *     <li>The server device must be the Publisher device!
+         *     <li>The port information can only be specified on secure links, specified using
+         *     {@link #setPskPassphrase(String)}.
+         * </ul>
+         *
+         * @param port A positive integer indicating the port to be used for communication.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull Builder setPort(int port) {
+            if (port <= 0 || port > 65535) {
+                throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
+            }
+            mPort = port;
+            return this;
+        }
+
+        /**
+         * Configure the transport protocol which will be used to create a connection over this
+         * link. This configuration should only be done on the server device, e.g. the device
+         * creating the {@link java.net.ServerSocket} for TCP.
+         * <p>Notes:
+         * <ul>
+         *     <li>The server device must be the Publisher device!
+         *     <li>The transport protocol information can only be specified on secure links,
+         *     specified using {@link #setPskPassphrase(String)}.
+         * </ul>
+         * The transport protocol number is assigned by the Internet Assigned Numbers Authority
+         * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
+         *
+         * @param transportProtocol The transport protocol to be used for communication.
+         * @return the current {@link Builder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull Builder setTransportProtocol(int transportProtocol) {
+            if (transportProtocol < 0 || transportProtocol > 255) {
+                throw new IllegalArgumentException(
+                        "The transport protocol must be in range [0, 255]");
+            }
+            mTransportProtocol = transportProtocol;
+            return this;
+        }
+
+        /**
+         * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)}
+         * for a WiFi Aware connection (link) to the specified peer. The
+         * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+         * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+         * <p> The default builder constructor will initialize a NetworkSpecifier which requests an
+         * open (non-encrypted) link. To request an encrypted link use the
+         * {@link #setPskPassphrase(String)} builder method.
+         *
+         * @return A {@link NetworkSpecifier} to be used to construct
+         * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
+         * to {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+         * android.net.ConnectivityManager.NetworkCallback)}
+         * [or other varieties of that API].
+         */
+        public @NonNull WifiAwareNetworkSpecifier build() {
+            if (mDiscoverySession == null) {
+                throw new IllegalStateException("Null discovery session!?");
+            }
+            if (mPskPassphrase != null & mPmk != null) {
+                throw new IllegalStateException(
+                        "Can only specify a Passphrase or a PMK - not both!");
+            }
+
+            int role = mDiscoverySession instanceof SubscribeDiscoverySession
+                    ? WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+                    : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+            if (mPort != 0 || mTransportProtocol != -1) {
+                if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
+                    throw new IllegalStateException(
+                            "Port and transport protocol information can only "
+                                    + "be specified on the Publisher device (which is the server");
+                }
+                if (TextUtils.isEmpty(mPskPassphrase) && mPmk == null) {
+                    throw new IllegalStateException("Port and transport protocol information can "
+                            + "only be specified on a secure link");
+                }
+            }
+
+            if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
+                throw new IllegalStateException("Null peerHandle!?");
+            }
+
+            return new WifiAwareNetworkSpecifier(
+                    WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
+                    mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
+                    null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
+        }
+    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 245b304..3c97813 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -213,7 +213,7 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+     *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
      * <p>
      * To set up an encrypted link use the
      * {@link #createNetworkSpecifierPassphrase(int, byte[], String)} API.
@@ -254,7 +254,7 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+     *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
      *
      * @param role  The role of this device:
      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
@@ -300,7 +300,7 @@
      *     This API is targeted for applications which can obtain the peer MAC address using OOB
      *     (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
      *     when using Aware discovery use the alternative network specifier method -
-     *     {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+     *     {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
      *
      * @param role  The role of this device:
      *              {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index b303496..0ce5d66 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -70,7 +70,7 @@
         assertTrue(readWifiInfo.isOsuAp());
         assertTrue(readWifiInfo.isPasspointAp());
         assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
-        assertEquals(TEST_FQDN, readWifiInfo.getFqdn());
-        assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getProviderFriendlyName());
+        assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
+        assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 3cc96bf..657a338 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -958,9 +958,8 @@
         WifiAwareNetworkSpecifier ns =
                 (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen(
                         peerHandle);
-        WifiAwareNetworkSpecifier nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager
-                .NetworkSpecifierBuilder().setDiscoverySession(publishSession.getValue())
-                .setPeerHandle(peerHandle).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession.getValue()).setPeerHandle(peerHandle).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -980,9 +979,9 @@
         // (4) request an encrypted (PMK) network specifier from the session
         ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk(
                 peerHandle, pmk);
-        nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
-                .setPmk(pmk).setPort(port).setTransportProtocol(transportProtocol).build();
+        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).setPort(
+                port).setTransportProtocol(transportProtocol).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1006,10 +1005,9 @@
                 (WifiAwareNetworkSpecifier) publishSession.getValue()
                         .createNetworkSpecifierPassphrase(
                         peerHandle, passphrase);
-        nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
-                .setPskPassphrase(passphrase).setPort(port).setTransportProtocol(transportProtocol)
-                .build();
+        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
+                passphrase).setPort(port).setTransportProtocol(transportProtocol).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1257,14 +1255,14 @@
         // (3) create network specifier
         if (doPmk) {
             if (useBuilder) {
-                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
                         publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).build();
             } else {
                 publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
             }
         } else {
             if (useBuilder) {
-                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
                         publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
                         passphrase).build();
             } else {
@@ -1355,10 +1353,8 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                        .setPmk(pmk).setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession).setPeerHandle(peerHandle).setPmk(pmk).setPort(port).build();
     }
 
     /**
@@ -1372,10 +1368,8 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                        .setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession).setPeerHandle(peerHandle).setPort(port).build();
     }
 
     /**
@@ -1389,10 +1383,8 @@
 
         DiscoverySession subscribeSession = executeSessionStartup(false);
 
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                        .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
-                        .setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                subscribeSession).setPeerHandle(peerHandle).setPort(port).build();
     }
 
     /**
@@ -1411,8 +1403,7 @@
         DiscoverySession publishSession = executeSessionStartup(true);
 
         try {
-            WifiAwareNetworkSpecifier nsb =
-                    (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
                             .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
                             .setPmk(pmk).setTransportProtocol(tpNegative).build();
             assertTrue("No exception on negative transport protocol!", false);
@@ -1420,23 +1411,19 @@
             // nop - exception is correct!
         }
         try {
-            WifiAwareNetworkSpecifier nsb =
-                    (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
                             .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
                             .setPmk(pmk).setTransportProtocol(tpTooLarge).build();
             assertTrue("No exception on >255 transport protocol!", false);
         } catch (IllegalArgumentException e) {
             // nop - exception is correct!
         }
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
                         .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
                         .setPmk(pmk).setTransportProtocol(tpSmallest).build();
-        nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                        .setDiscoverySession(
-                                publishSession).setPeerHandle(peerHandle).setPmk(
-                        pmk).setTransportProtocol(tpLargest).build();
+        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+                publishSession).setPeerHandle(peerHandle).setPmk(pmk).setTransportProtocol(
+                tpLargest).build();
     }
 
     /**
@@ -1450,8 +1437,7 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
                         .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
                         .setTransportProtocol(transportProtocol).build();
     }
@@ -1467,8 +1453,7 @@
 
         DiscoverySession subscribeSession = executeSessionStartup(false);
 
-        WifiAwareNetworkSpecifier nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
                         .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
                         .setTransportProtocol(transportProtocol).build();
     }