Merge "Verify permissions are only held by media stack."
diff --git a/api/current.txt b/api/current.txt
index 487dfd6..014ba9d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6600,7 +6600,6 @@
     method @Nullable public String[] getAccountTypesWithManagementDisabled();
     method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
-    method public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6675,7 +6674,6 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(@NonNull android.content.ComponentName);
     method public boolean isAffiliatedUser();
-    method public boolean isAlwaysOnVpnLockdownEnabled(@NonNull android.content.ComponentName);
     method public boolean isApplicationHidden(@NonNull android.content.ComponentName, String);
     method public boolean isBackupServiceEnabled(@NonNull android.content.ComponentName);
     method @Deprecated public boolean isCallerApplicationRestrictionsManagingPackage();
@@ -6713,7 +6711,6 @@
     method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
     method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
     method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
-    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -6790,7 +6787,7 @@
     method public void uninstallCaCert(@Nullable android.content.ComponentName, byte[]);
     method public boolean updateOverrideApn(@NonNull android.content.ComponentName, int, @NonNull android.telephony.data.ApnSetting);
     method public void wipeData(int);
-    method public void wipeData(int, CharSequence);
+    method public void wipeData(int, @NonNull CharSequence);
     field public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
     field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
@@ -6934,6 +6931,7 @@
     field public static final int WIPE_EUICC = 4; // 0x4
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
+    field public static final int WIPE_SILENTLY = 8; // 0x8
   }
 
   public abstract static class DevicePolicyManager.InstallUpdateCallback {
@@ -29842,7 +29840,7 @@
     method @Deprecated public boolean disableNetwork(int);
     method @Deprecated public boolean disconnect();
     method @Deprecated public boolean enableNetwork(int, boolean);
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
@@ -30333,26 +30331,26 @@
   }
 
   public class WifiP2pManager {
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void addServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void clearLocalServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void clearServiceRequests(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void createGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pConfig, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void createGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pConfig, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
     method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
     method public void requestDiscoveryState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.DiscoveryStateListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
     method public void requestNetworkInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.NetworkInfoListener);
     method public void requestP2pState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.P2pStateListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
     method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener);
     method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener);
     method public void setUpnpServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.UpnpServiceResponseListener);
@@ -44037,7 +44035,9 @@
     field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
     field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+    field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+    field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
@@ -53492,6 +53492,7 @@
 
   public final class TextClassificationManager {
     method @NonNull public android.view.textclassifier.TextClassifier createTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext);
+    method @NonNull public android.view.textclassifier.TextClassifier getLocalTextClassifier();
     method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
     method public void setTextClassificationSessionFactory(@Nullable android.view.textclassifier.TextClassificationSessionFactory);
     method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
@@ -53569,7 +53570,7 @@
   public final class TextClassifierEvent implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public int[] getActionIndices();
-    method @Nullable public String getEntityType();
+    method @NonNull public String[] getEntityTypes();
     method public int getEventCategory();
     method @Nullable public android.view.textclassifier.TextClassificationContext getEventContext();
     method public int getEventIndex();
@@ -53582,6 +53583,7 @@
     method public int getRelativeWordEndIndex();
     method public int getRelativeWordStartIndex();
     method @Nullable public String getResultId();
+    method public float getScore();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3
     field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4
@@ -53616,7 +53618,7 @@
     ctor public TextClassifierEvent.Builder(int, int);
     method @NonNull public android.view.textclassifier.TextClassifierEvent build();
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(@NonNull int...);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityType(@Nullable String);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityTypes(@NonNull java.lang.String...);
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(@Nullable android.view.textclassifier.TextClassificationContext);
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int);
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long);
@@ -53627,6 +53629,7 @@
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int);
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int);
     method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setResultId(@Nullable String);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setScore(float);
   }
 
   public final class TextLanguage implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 05e04e9..49abe28 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -883,8 +883,8 @@
 
   public final class ClassificationsRequest implements android.os.Parcelable {
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
+    method @Nullable public android.os.Bundle getExtras();
+    method @NonNull public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
   }
@@ -898,8 +898,8 @@
   public final class ContentClassification implements android.os.Parcelable {
     ctor public ContentClassification(@NonNull String, @NonNull android.os.Bundle);
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public String getId();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public String getId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
   }
@@ -907,8 +907,8 @@
   public final class ContentSelection implements android.os.Parcelable {
     ctor public ContentSelection(@NonNull String, @NonNull android.os.Bundle);
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public String getId();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public String getId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
   }
@@ -930,8 +930,8 @@
 
   public final class SelectionsRequest implements android.os.Parcelable {
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public android.graphics.Point getInterestPoint();
+    method @Nullable public android.os.Bundle getExtras();
+    method @Nullable public android.graphics.Point getInterestPoint();
     method public int getTaskId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
@@ -1053,6 +1053,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @RequiresPermission("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 String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
   public interface RoleManagerCallback {
@@ -1158,14 +1159,18 @@
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean getSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
+    field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+    field public static final String EXTRA_SILENCE_ENABLED = "android.bluetooth.device.extra.SILENCE_ENABLED";
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
@@ -1807,9 +1812,16 @@
   }
 
   public final class ColorDisplayManager {
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getNightDisplayAutoMode();
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getTransformCapabilities();
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String, @IntRange(from=0, to=100) int);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayAutoMode(int);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomEndTime(@NonNull java.time.LocalTime);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomStartTime(@NonNull java.time.LocalTime);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(@IntRange(from=0, to=100) int);
+    field public static final int AUTO_MODE_CUSTOM_TIME = 1; // 0x1
+    field public static final int AUTO_MODE_DISABLED = 0; // 0x0
+    field public static final int AUTO_MODE_TWILIGHT = 2; // 0x2
     field public static final int CAPABILITY_HARDWARE_ACCELERATION_GLOBAL = 2; // 0x2
     field public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 4; // 0x4
     field public static final int CAPABILITY_NONE = 0; // 0x0
@@ -1841,9 +1853,15 @@
   public final class HdmiControlManager {
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
     method @Nullable public android.hardware.hdmi.HdmiClient getClient(int);
+    method @Nullable public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList();
+    method public int getPhysicalAddress();
     method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+    method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
     method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient();
+    method public boolean isRemoteDeviceConnected(android.hardware.hdmi.HdmiDeviceInfo);
+    method public void powerOffRemoteDevice(android.hardware.hdmi.HdmiDeviceInfo);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
+    method public void requestRemoteDeviceToBecomeActiveSource(android.hardware.hdmi.HdmiDeviceInfo);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
     field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
     field public static final int AVR_VOLUME_MUTED = 101; // 0x65
@@ -1933,6 +1951,9 @@
     field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
   }
 
+  @IntDef({android.hardware.hdmi.HdmiControlManager.RESULT_SUCCESS, android.hardware.hdmi.HdmiControlManager.RESULT_TIMEOUT, android.hardware.hdmi.HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_ALREADY_IN_PROGRESS, android.hardware.hdmi.HdmiControlManager.RESULT_EXCEPTION, android.hardware.hdmi.HdmiControlManager.RESULT_INCORRECT_MODE, android.hardware.hdmi.HdmiControlManager.RESULT_COMMUNICATION_FAILED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface HdmiControlManager.ControlCallbackResult {
+  }
+
   public static interface HdmiControlManager.HotplugEventListener {
     method public void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
   }
@@ -2059,6 +2080,16 @@
   public abstract static class HdmiRecordSources.RecordSource {
   }
 
+  public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient {
+    method public int getDeviceType();
+    method public void selectPort(int, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
+    method public void selectPort(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
+  }
+
+  public static interface HdmiSwitchClient.OnSelectListener {
+    method public void onSelect(@android.hardware.hdmi.HdmiControlManager.ControlCallbackResult int);
+  }
+
   public class HdmiTimerRecordSources {
     method public static boolean checkTimerRecordSource(int, byte[]);
     method public static android.hardware.hdmi.HdmiTimerRecordSources.Duration durationOf(int, int);
@@ -4647,7 +4678,7 @@
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
-    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     method public boolean isDeviceToDeviceRttSupported();
@@ -5655,6 +5686,11 @@
     method public void onPropertyChanged(String, String, String);
   }
 
+  public static interface DeviceConfig.Storage {
+    field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
+    field public static final String NAMESPACE = "storage";
+  }
+
   public static interface DeviceConfig.Telephony {
     field public static final String NAMESPACE = "telephony";
     field public static final String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer";
@@ -7980,10 +8016,10 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
     field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
     field @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
-    field public static final String ACTION_PROFILE_SELECTION = "android.telephony.euicc.action.PROFILE_SELECTION";
     field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
     field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
     field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
+    field public static final int EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED = 4; // 0x4
     field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2
     field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1
     field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3
@@ -8676,12 +8712,20 @@
 
   public class ProvisioningManager {
     method public static android.telephony.ims.ProvisioningManager createForSubscriptionId(android.content.Context, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
+    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningIntValue(int, int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningStringValue(int, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+    field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
+    field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
+    field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
+    field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
+    field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
+    field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
   }
 
   public static class ProvisioningManager.Callback {
diff --git a/api/test-current.txt b/api/test-current.txt
index f1795c7..0f2ba12 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -15,6 +15,10 @@
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
+  public static final class R.array {
+    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
+  }
+
 }
 
 package android.animation {
@@ -333,6 +337,7 @@
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
   public interface RoleManagerCallback {
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 3defdc5..062ba65 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -102,7 +102,17 @@
         String op = nextArg();
         Slog.v(TAG, "Running " + op + " for user:" + userId);
 
-        if (!isBmgrActive(userId)) {
+        if (mBmgr == null) {
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+            return;
+        }
+
+        if ("activate".equals(op)) {
+            doActivateService(userId);
+            return;
+        }
+
+        if (!isBackupActive(userId)) {
             return;
         }
 
@@ -175,12 +185,7 @@
         showUsage();
     }
 
-    boolean isBmgrActive(@UserIdInt int userId) {
-        if (mBmgr == null) {
-            System.err.println(BMGR_NOT_RUNNING_ERR);
-            return false;
-        }
-
+    boolean isBackupActive(@UserIdInt int userId) {
         try {
             if (!mBmgr.isBackupServiceActive(userId)) {
                 System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -845,6 +850,27 @@
         }
     }
 
+    private void doActivateService(int userId) {
+        String arg = nextArg();
+        if (arg == null) {
+            showUsage();
+            return;
+        }
+
+        try {
+            boolean activate = Boolean.parseBoolean(arg);
+            mBmgr.setBackupServiceActive(userId, activate);
+            System.out.println(
+                    "Backup service now "
+                            + (activate ? "activated" : "deactivated")
+                            + " for user "
+                            + userId);
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -880,6 +906,7 @@
         System.err.println("       bmgr backupnow [--monitor|--monitor-verbose] --all|PACKAGE...");
         System.err.println("       bmgr cancel backups");
         System.err.println("       bmgr init TRANSPORT...");
+        System.err.println("       bmgr activate BOOL");
         System.err.println("");
         System.err.println("The '--user' option specifies the user on which the operation is run.");
         System.err.println("It must be the first argument before the operation.");
@@ -946,6 +973,11 @@
         System.err.println("");
         System.err.println("The 'init' command initializes the given transports, wiping all data");
         System.err.println("from their backing data stores.");
+        System.err.println("");
+        System.err.println("The 'activate' command activates or deactivates the backup service.");
+        System.err.println("If the argument is 'true' it will be activated, otherwise it will be");
+        System.err.println("deactivated. When deactivated, the service will not be running and no");
+        System.err.println("operations can be performed until activation.");
     }
 
     private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c455ac0..0c581f3 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -39,6 +39,7 @@
 using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::UidHasWriteAccessToPath;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
   std::string target_apk_path;
@@ -66,6 +67,13 @@
     return false;
   }
 
+  const uid_t uid = getuid();
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    out_error << "error: uid " << uid << " does not have write access to " << idmap_path
+              << std::endl;
+    return false;
+  }
+
   PolicyBitmask fulfilled_policies = 0;
   if (auto result = PoliciesToBitmask(policies, out_error)) {
     fulfilled_policies |= *result;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index a3c7527..f30ce9b 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -27,6 +27,7 @@
 
 #include "android-base/macros.h"
 #include "android-base/stringprintf.h"
+#include "binder/IPCThreadState.h"
 #include "utils/String8.h"
 #include "utils/Trace.h"
 
@@ -38,18 +39,19 @@
 
 #include "idmap2d/Idmap2Service.h"
 
+using android::IPCThreadState;
 using android::binder::Status;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
 using android::idmap2::PolicyBitmask;
 using android::idmap2::Result;
+using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::UidHasWriteAccessToPath;
 
 namespace {
 
-constexpr const char* kIdmapCacheDir = "/data/resource-cache";
-
 Status ok() {
   return Status::ok();
 }
@@ -77,7 +79,13 @@
 Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
+  const uid_t uid = IPCThreadState::self()->getCallingUid();
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    *_aidl_return = false;
+    return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
+                                    idmap_path.c_str(), uid));
+  }
   if (unlink(idmap_path.c_str()) != 0) {
     *_aidl_return = false;
     return error("failed to unlink " + idmap_path + ": " + strerror(errno));
@@ -118,6 +126,13 @@
 
   const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
 
+  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  const uid_t uid = IPCThreadState::self()->getCallingUid();
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
+                                    idmap_path.c_str(), uid));
+  }
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     return error("failed to load apk " + target_apk_path);
@@ -137,7 +152,6 @@
   }
 
   umask(kIdmapFilePermissionMask);
-  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   std::ofstream fout(idmap_path);
   if (fout.fail()) {
     return error("failed to open idmap path " + idmap_path);
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index 5c41c49..3f03236 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -17,6 +17,8 @@
 #ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
 #define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
 
+#include <sys/types.h>
+
 #include <functional>
 #include <memory>
 #include <string>
@@ -24,6 +26,7 @@
 
 namespace android::idmap2::utils {
 
+constexpr const char* kIdmapCacheDir = "/data/resource-cache";
 constexpr const mode_t kIdmapFilePermissionMask = 0133;  // u=rw,g=r,o=r
 
 typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)>
@@ -35,6 +38,8 @@
 
 std::unique_ptr<std::string> ReadFile(const std::string& path);
 
+bool UidHasWriteAccessToPath(uid_t uid, const std::string& path);
+
 }  // namespace android::idmap2::utils
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp
index 0255727..a9b68cd 100644
--- a/cmds/idmap2/libidmap2/FileUtils.cpp
+++ b/cmds/idmap2/libidmap2/FileUtils.cpp
@@ -19,12 +19,20 @@
 #include <unistd.h>
 
 #include <cerrno>
+#include <climits>
+#include <cstdlib>
+#include <cstring>
 #include <fstream>
 #include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "private/android_filesystem_config.h"
+
 #include "idmap2/FileUtils.h"
 
 namespace android::idmap2::utils {
@@ -77,4 +85,26 @@
   return r == 0 ? std::move(str) : nullptr;
 }
 
+#ifdef __ANDROID__
+bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) {
+  // resolve symlinks and relative paths; the directories must exist
+  std::string canonical_path;
+  if (!base::Realpath(base::Dirname(path), &canonical_path)) {
+    return false;
+  }
+
+  const std::string cache_subdir = base::StringPrintf("%s/", kIdmapCacheDir);
+  if (canonical_path == kIdmapCacheDir ||
+      canonical_path.compare(0, cache_subdir.size(), cache_subdir) == 0) {
+    // limit access to /data/resource-cache to root and system
+    return uid == AID_ROOT || uid == AID_SYSTEM;
+  }
+  return true;
+}
+#else
+bool UidHasWriteAccessToPath(uid_t uid ATTRIBUTE_UNUSED, const std::string& path ATTRIBUTE_UNUSED) {
+  return true;
+}
+#endif
+
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index d9d9a7f..45f84fe 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -22,6 +22,8 @@
 #include "gtest/gtest.h"
 
 #include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "private/android_filesystem_config.h"
 
 #include "idmap2/FileUtils.h"
 
@@ -71,4 +73,25 @@
   close(pipefd[0]);
 }
 
+#ifdef __ANDROID__
+TEST(FileUtilsTests, UidHasWriteAccessToPath) {
+  constexpr const char* tmp_path = "/data/local/tmp/test@idmap";
+  const std::string cache_path(base::StringPrintf("%s/test@idmap", kIdmapCacheDir));
+  const std::string sneaky_cache_path(base::StringPrintf("/data/../%s/test@idmap", kIdmapCacheDir));
+
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, tmp_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, cache_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, sneaky_cache_path));
+
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, tmp_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, cache_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, sneaky_cache_path));
+
+  constexpr const uid_t AID_SOME_APP = AID_SYSTEM + 1;
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SOME_APP, tmp_path));
+  ASSERT_FALSE(UidHasWriteAccessToPath(AID_SOME_APP, cache_path));
+  ASSERT_FALSE(UidHasWriteAccessToPath(AID_SOME_APP, sneaky_cache_path));
+}
+#endif
+
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 4334fa6..c550eaf 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
 #include "gtest/gtest.h"
 
 #include "androidfw/PosixUtils.h"
+#include "private/android_filesystem_config.h"
 
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
@@ -69,9 +70,23 @@
     ASSERT_NO_FATAL_FAILURE(AssertIdmap(idmap_ref, target_apk_path, overlay_apk_path)); \
   } while (0)
 
+#ifdef __ANDROID__
+#define SKIP_TEST_IF_CANT_EXEC_IDMAP2           \
+  do {                                          \
+    const uid_t uid = getuid();                 \
+    if (uid != AID_ROOT && uid != AID_SYSTEM) { \
+      GTEST_SKIP();                             \
+    }                                           \
+  } while (0)
+#else
+#define SKIP_TEST_IF_CANT_EXEC_IDMAP2
+#endif
+
 }  // namespace
 
 TEST_F(Idmap2BinaryTests, Create) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -97,6 +112,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Dump) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -144,6 +161,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Scan) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk";
   const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk";
   const std::string idmap_static_1_path =
@@ -236,6 +255,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Lookup) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -285,6 +306,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   const std::string invalid_target_apk_path = GetTestDataPath() + "/DOES-NOT-EXIST";
 
   // missing mandatory options
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8fb01b4..d6b4737f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2492,24 +2492,32 @@
 
 /*
  * Logs when a binary push state changes.
- * Logged in Play store
+ * Logged by the installer via public api.
  */
 message BinaryPushStateChanged {
-    // Binary package name.
-    optional string binary_name = 1;
-    // Version code.
-    optional int64 version = 2;
-    // State
+    // Name of the train.
+    optional string train_name = 1;
+    // Version code for a "train" of packages that need to be installed atomically
+    optional int64 train_version_code = 2;
+    // After installation of this package, device requires a restart.
+    optional bool requires_staging = 3;
+    // Rollback should be enabled for this install.
+    optional bool rollback_enabled = 4;
+    // Requires low latency monitoring if possible.
+    optional bool requires_low_latency_monitor = 5;
+
     enum State {
-        STATE_UNKNOWN = 0;
-        DOWNLOAD_START = 1;
-        DOWNLOAD_DONE = 2;
-        INSTALL_START = 3;
-        INSTALL_DONE = 4;
-        REBOOT_START = 5;
-        REBOOT_DONE = 6;
+        UNKNOWN = 0;
+        INSTALL_REQUESTED = 1;
+        INSTALL_STARTED = 2;
+        INSTALL_STAGED_NOT_READY = 3;
+        INSTALL_STAGED_READY = 4;
+        INSTALL_SUCCESS = 5;
+        INSTALL_FAILURE = 6;
+        INSTALL_CANCELLED = 7;
+        INSTALLER_ROLLBACK_REQUESTED = 8;
     }
-    optional State state = 3;
+    optional State state = 6;
 }
 
 /** Represents USB port overheat event. */
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 4d3711a..4739867 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager.StackInfo;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.display.DisplayManager;
@@ -119,6 +120,7 @@
 
     /** Callback that notifies when the container is ready or destroyed. */
     public abstract static class StateCallback {
+
         /**
          * Called when the container is ready for launching activities. Calling
          * {@link #startActivity(Intent)} prior to this callback will result in an
@@ -127,6 +129,7 @@
          * @see #startActivity(Intent)
          */
         public abstract void onActivityViewReady(ActivityView view);
+
         /**
          * Called when the container can no longer launch activities. Calling
          * {@link #startActivity(Intent)} after this callback will result in an
@@ -135,11 +138,24 @@
          * @see #startActivity(Intent)
          */
         public abstract void onActivityViewDestroyed(ActivityView view);
+
+        /**
+         * Called when a task is created inside the container.
+         * This is a filtered version of {@link TaskStackListener}
+         */
+        public void onTaskCreated(int taskId, ComponentName componentName) { }
+
         /**
          * Called when a task is moved to the front of the stack inside the container.
          * This is a filtered version of {@link TaskStackListener}
          */
         public void onTaskMovedToFront(ActivityManager.StackInfo stackInfo) { }
+
+        /**
+         * Called when a task is about to be removed from the stack inside the container.
+         * This is a filtered version of {@link TaskStackListener}
+         */
+        public void onTaskRemovalStarted(int taskId) { }
     }
 
     /**
@@ -508,14 +524,45 @@
 
         @Override
         public void onTaskMovedToFront(int taskId) throws RemoteException {
-            if (mActivityViewCallback  != null) {
-                StackInfo stackInfo = getTopMostStackInfo();
-                // if StackInfo was null or unrelated to the "move to front" then there's no use
-                // notifying the callback
-                if (stackInfo != null
-                        && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                    mActivityViewCallback.onTaskMovedToFront(stackInfo);
-                }
+            if (mActivityViewCallback  == null) {
+                return;
+            }
+
+            StackInfo stackInfo = getTopMostStackInfo();
+            // if StackInfo was null or unrelated to the "move to front" then there's no use
+            // notifying the callback
+            if (stackInfo != null
+                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                mActivityViewCallback.onTaskMovedToFront(stackInfo);
+            }
+        }
+
+        @Override
+        public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
+            if (mActivityViewCallback  == null) {
+                return;
+            }
+
+            StackInfo stackInfo = getTopMostStackInfo();
+            // if StackInfo was null or unrelated to the task creation then there's no use
+            // notifying the callback
+            if (stackInfo != null
+                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                mActivityViewCallback.onTaskCreated(taskId, componentName);
+            }
+        }
+
+        @Override
+        public void onTaskRemovalStarted(int taskId) throws RemoteException {
+            if (mActivityViewCallback  == null) {
+                return;
+            }
+            StackInfo stackInfo = getTopMostStackInfo();
+            // if StackInfo was null or task is on a different display then there's no use
+            // notifying the callback
+            if (stackInfo != null
+                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                mActivityViewCallback.onTaskRemovalStarted(taskId);
             }
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ab2430c..364d3c9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -39,6 +39,7 @@
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
@@ -1712,6 +1713,12 @@
     /** @hide */
     public static final String KEY_HISTORICAL_OPS = "historical_ops";
 
+    /** System properties for debug logging of noteOp call sites */
+    private static final String DEBUG_LOGGING_ENABLE_PROP = "appops.logging_enabled";
+    private static final String DEBUG_LOGGING_PACKAGES_PROP = "appops.logging_packages";
+    private static final String DEBUG_LOGGING_OPS_PROP = "appops.logging_ops";
+    private static final String DEBUG_LOGGING_TAG = "AppOpsManager";
+
     /**
      * Retrieve the op switch that controls the given operation.
      * @hide
@@ -4469,6 +4476,7 @@
      */
     @UnsupportedAppUsage
     public int noteOpNoThrow(int op, int uid, String packageName) {
+        logNoteOpIfNeeded(op, packageName);
         try {
             return mService.noteOperation(op, uid, packageName);
         } catch (RemoteException e) {
@@ -4834,4 +4842,45 @@
 
         return AppOpsManager.MODE_DEFAULT;
     }
+
+    private static void logNoteOpIfNeeded(int op, String callingPackage) {
+        // Check if debug logging propety is enabled.
+        if (!SystemProperties.getBoolean(DEBUG_LOGGING_ENABLE_PROP, false)) {
+            return;
+        }
+        // Check if this package should be logged.
+        String packages = SystemProperties.get(DEBUG_LOGGING_PACKAGES_PROP, "");
+        if (!"".equals(packages) && callingPackage != null) {
+            boolean found = false;
+            for (String pkg : packages.split(",")) {
+                if (callingPackage.equals(pkg)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return;
+            }
+        }
+        String opStr = opToName(op);
+        // Check if this app op should be logged
+        String logOps = SystemProperties.get(DEBUG_LOGGING_OPS_PROP, "");
+        if (!"".equals(logOps)) {
+            boolean found = false;
+            for (String logOp : logOps.split(",")) {
+                if (opStr.equals(logOp)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return;
+            }
+        }
+
+        // Log a stack trace
+        Exception here = new Exception("HERE!");
+        android.util.Log.i(DEBUG_LOGGING_TAG, "Note operation package= " + callingPackage
+                + " op= " + opStr, here);
+    }
 }
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index cc6c999..db6ad3d 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -434,6 +434,11 @@
     void registerRemoteAnimationForNextActivityStart(in String packageName,
            in RemoteAnimationAdapter adapter);
 
+    /**
+     * Registers remote animations for a display.
+     */
+    void registerRemoteAnimationsForDisplay(int displayId, in RemoteAnimationDefinition definition);
+
     /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
     void alwaysShowUnsupportedCompileSdkWarning(in ComponentName activity);
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b8d748d..b405d0c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5257,7 +5257,11 @@
          * @hide
          */
         public RemoteViews makeAmbientNotification() {
-            return createHeadsUpContentView(false /* increasedHeight */);
+            RemoteViews headsUpContentView = createHeadsUpContentView(false /* increasedHeight */);
+            if (headsUpContentView != null) {
+                return headsUpContentView;
+            }
+            return createContentView();
         }
 
         private void hideLine1Text(RemoteViews result) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ee91fa1..2514eee 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3980,6 +3980,10 @@
      */
     public static final int WIPE_EUICC = 0x0004;
 
+    /**
+     * Flag for {@link #wipeData(int)}: won't show reason for wiping to the user.
+     */
+    public static final int WIPE_SILENTLY = 0x0008;
 
     /**
      * Ask that all user data be wiped. If called as a secondary user, the user will be removed and
@@ -3991,9 +3995,10 @@
      * be able to call this method; if it has not, a security exception will be thrown.
      *
      * @param flags Bit mask of additional options: currently supported flags are
-     *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+     *            {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA},
+     *            {@link #WIPE_EUICC} and {@link #WIPE_SILENTLY}.
      * @throws SecurityException if the calling application does not own an active administrator
-     *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
+     *            that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
      */
     public void wipeData(int flags) {
         throwIfParentInstance("wipeData");
@@ -4013,16 +4018,21 @@
      * be able to call this method; if it has not, a security exception will be thrown.
      *
      * @param flags Bit mask of additional options: currently supported flags are
-     *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+     *            {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA} and
+     *            {@link #WIPE_EUICC}.
      * @param reason a string that contains the reason for wiping data, which can be
-     *            presented to the user. If the string is null or empty, user won't be notified.
+     *            presented to the user.
      * @throws SecurityException if the calling application does not own an active administrator
-     *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
-     * @throws IllegalArgumentException if the input reason string is null or empty.
+     *            that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
+     * @throws IllegalArgumentException if the input reason string is null or empty, or if
+     *            {@link #WIPE_SILENTLY} is set.
      */
-    public void wipeData(int flags, CharSequence reason) {
+    public void wipeData(int flags, @NonNull CharSequence reason) {
         throwIfParentInstance("wipeData");
-        wipeDataInternal(flags, reason != null ? reason.toString() : null);
+        Preconditions.checkNotNull(reason, "reason string is null");
+        Preconditions.checkStringNotEmpty(reason, "reason string is empty");
+        Preconditions.checkArgument((flags & WIPE_SILENTLY) == 0, "WIPE_SILENTLY cannot be set");
+        wipeDataInternal(flags, reason.toString());
     }
 
     /**
@@ -4033,7 +4043,7 @@
      * @see #wipeData(int, CharSequence)
      * @hide
      */
-    private void wipeDataInternal(int flags, String wipeReasonForUser) {
+    private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
         if (mService != null) {
             try {
                 mService.wipeDataWithReason(flags, wipeReasonForUser);
@@ -5049,16 +5059,11 @@
     }
 
     /**
-     * Service-specific error code used in implementation of {@code setAlwaysOnVpnPackage} methods.
-     * @hide
-     */
-    public static final int ERROR_VPN_PACKAGE_NOT_FOUND = 1;
-
-    /**
      * Called by a device or profile owner to configure an always-on VPN connection through a
      * specific application for the current user. This connection is automatically granted and
      * persisted after a reboot.
-     * <p> To support the always-on feature, an app must
+     * <p>
+     * To support the always-on feature, an app must
      * <ul>
      *     <li>declare a {@link android.net.VpnService} in its manifest, guarded by
      *         {@link android.Manifest.permission#BIND_VPN_SERVICE};</li>
@@ -5067,13 +5072,12 @@
      *         {@link android.net.VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}.</li>
      * </ul>
      * The call will fail if called with the package name of an unsupported VPN app.
-     * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
-     * of the VPN provider could break networking for all apps.
      *
      * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
      *        remove an existing always-on VPN configuration.
      * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
-     *        {@code false} otherwise. This has no effect when clearing.
+     *        {@code false} otherwise. This carries the risk that any failure of the VPN provider
+     *        could break networking for all apps. This has no effect when clearing.
      * @throws SecurityException if {@code admin} is not a device or a profile owner.
      * @throws NameNotFoundException if {@code vpnPackage} is not installed.
      * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
@@ -5082,46 +5086,11 @@
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
             boolean lockdownEnabled)
             throws NameNotFoundException, UnsupportedOperationException {
-        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
-    }
-
-    /**
-     * A version of {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} that allows the
-     * admin to specify a set of apps that should be able to access the network directly when VPN
-     * is not connected. When VPN connects these apps switch over to VPN if allowed to use that VPN.
-     * System apps can always bypass VPN.
-     * <p> Note that the system doesn't update the whitelist when packages are installed or
-     * uninstalled, the admin app must call this method to keep the list up to date.
-     *
-     * @param vpnPackage package name for an installed VPN app on the device, or {@code null}
-     *         to remove an existing always-on VPN configuration
-     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
-     *         {@code false} otherwise. This has no effect when clearing.
-     * @param lockdownWhitelist Packages that will be able to access the network directly when VPN
-     *         is in lockdown mode but not connected. Has no effect when clearing.
-     * @throws SecurityException if {@code admin} is not a device or a profile
-     *         owner.
-     * @throws NameNotFoundException if {@code vpnPackage} or one of
-     *         {@code lockdownWhitelist} is not installed.
-     * @throws UnsupportedOperationException if {@code vpnPackage} exists but does
-     *         not support being set as always-on, or if always-on VPN is not
-     *         available.
-     */
-    public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
-            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
-            throws NameNotFoundException, UnsupportedOperationException {
         throwIfParentInstance("setAlwaysOnVpnPackage");
         if (mService != null) {
             try {
-                mService.setAlwaysOnVpnPackage(
-                        admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
-            } catch (ServiceSpecificException e) {
-                switch (e.errorCode) {
-                    case ERROR_VPN_PACKAGE_NOT_FOUND:
-                        throw new NameNotFoundException(e.getMessage());
-                    default:
-                        throw new RuntimeException(
-                                "Unknown error setting always-on VPN: " + e.errorCode);
+                if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled)) {
+                    throw new NameNotFoundException(vpnPackage);
                 }
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -5130,51 +5099,6 @@
     }
 
     /**
-     * Called by device or profile owner to query whether current always-on VPN is configured in
-     * lockdown mode. Returns {@code false} when no always-on configuration is set.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     *
-     * @throws SecurityException if {@code admin} is not a device or a profile owner.
-     *
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean)
-     */
-    public boolean isAlwaysOnVpnLockdownEnabled(@NonNull ComponentName admin) {
-        throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
-        if (mService != null) {
-            try {
-                return mService.isAlwaysOnVpnLockdownEnabled(admin);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Called by device or profile owner to query the list of packages that are allowed to access
-     * the network directly when always-on VPN is in lockdown mode but not connected. Returns
-     * {@code null} when always-on VPN is not active or not in lockdown mode.
-     *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     *
-     * @throws SecurityException if {@code admin} is not a device or a profile owner.
-     *
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
-     */
-    public List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
-        throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
-        if (mService != null) {
-            try {
-                return mService.getAlwaysOnVpnLockdownWhitelist(admin);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-        return null;
-    }
-
-    /**
      * Called by a device or profile owner to read the name of the package administering an
      * always-on VPN connection for the current user. If there is no such package, or the always-on
      * VPN is provided by the system instead of by an application, {@code null} will be returned.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5790fda..1751a91c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -187,10 +187,8 @@
     void setCertInstallerPackage(in ComponentName who, String installerPackage);
     String getCertInstallerPackage(in ComponentName who);
 
-    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
+    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown);
     String getAlwaysOnVpnPackage(in ComponentName who);
-    boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
-    List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);
 
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
     void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
index 3f71518..9bb39e5 100644
--- a/core/java/android/app/contentsuggestions/ClassificationsRequest.java
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -26,6 +26,11 @@
 import java.util.List;
 
 /**
+ * Request object used when asking {@link ContentSuggestionsManager} to classify content selections.
+ *
+ * <p>The request contains a list of {@link ContentSelection} objects to be classified along with
+ * implementation specific extras.
+ *
  * @hide
  */
 @SystemApi
@@ -44,14 +49,14 @@
     /**
      * Return request selections.
      */
-    public List<ContentSelection> getSelections() {
+    public @NonNull List<ContentSelection> getSelections() {
         return mSelections;
     }
 
     /**
-     * Return the request extras.
+     * Return the request extras or {@code null} if there are none.
      */
-    public Bundle getExtras() {
+    public @Nullable Bundle getExtras() {
         return mExtras;
     }
 
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.java b/core/java/android/app/contentsuggestions/ContentClassification.java
index f18520f..2a00b40 100644
--- a/core/java/android/app/contentsuggestions/ContentClassification.java
+++ b/core/java/android/app/contentsuggestions/ContentClassification.java
@@ -23,6 +23,9 @@
 import android.os.Parcelable;
 
 /**
+ * Represents the classification of a content suggestion. The result of a
+ * {@link ClassificationsRequest} to {@link ContentSuggestionsManager}.
+ *
  * @hide
  */
 @SystemApi
@@ -32,6 +35,12 @@
     @NonNull
     private final Bundle mExtras;
 
+    /**
+     * Default constructor.
+     *
+     * @param classificationId implementation specific id for the selection /  classification.
+     * @param extras containing the classification data.
+     */
     public ContentClassification(@NonNull String classificationId, @NonNull Bundle extras) {
         mClassificationId = classificationId;
         mExtras = extras;
@@ -40,14 +49,14 @@
     /**
      * Return the classification id.
      */
-    public String getId() {
+    public @NonNull String getId() {
         return mClassificationId;
     }
 
     /**
      * Return the classification extras.
      */
-    public Bundle getExtras() {
+    public @NonNull Bundle getExtras() {
         return mExtras;
     }
 
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.java b/core/java/android/app/contentsuggestions/ContentSelection.java
index a8917f7..16b4f3f 100644
--- a/core/java/android/app/contentsuggestions/ContentSelection.java
+++ b/core/java/android/app/contentsuggestions/ContentSelection.java
@@ -23,6 +23,9 @@
 import android.os.Parcelable;
 
 /**
+ * Represents a suggested selection within a set of on screen content. The result of a
+ * {@link SelectionsRequest} to {@link ContentSuggestionsManager}.
+ *
  * @hide
  */
 @SystemApi
@@ -32,6 +35,12 @@
     @NonNull
     private final Bundle mExtras;
 
+    /**
+     * Default constructor.
+     *
+     * @param selectionId implementation specific id for the selection.
+     * @param extras containing the data that represents the selection.
+     */
     public ContentSelection(@NonNull String selectionId, @NonNull Bundle extras) {
         mSelectionId = selectionId;
         mExtras = extras;
@@ -40,14 +49,14 @@
     /**
      * Return the selection id.
      */
-    public String getId() {
+    public @NonNull String getId() {
         return mSelectionId;
     }
 
     /**
      * Return the selection extras.
      */
-    public Bundle getExtras() {
+    public @NonNull Bundle getExtras() {
         return mExtras;
     }
 
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java
index 16f3e6b..e3c8bc5 100644
--- a/core/java/android/app/contentsuggestions/SelectionsRequest.java
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -25,6 +25,12 @@
 import android.os.Parcelable;
 
 /**
+ * The request object used to request content selections from {@link ContentSuggestionsManager}.
+ *
+ * <p>Selections are requested for a given taskId as specified by
+ * {@link android.app.ActivityManager} and optionally take an interest point that specifies the
+ * point on the screen that should be considered as the most important.
+ *
  * @hide
  */
 @SystemApi
@@ -49,16 +55,17 @@
     }
 
     /**
-     * Return the request point of interest.
+     * Return the request point of interest or {@code null} if there is no point of interest for
+     * this request.
      */
-    public Point getInterestPoint() {
+    public @Nullable Point getInterestPoint() {
         return mInterestPoint;
     }
 
     /**
-     * Return the request extras.
+     * Return the request extras or {@code null} if there aren't any.
      */
-    public Bundle getExtras() {
+    public @Nullable Bundle getExtras() {
         return mExtras;
     }
 
@@ -99,6 +106,11 @@
         private Point mInterestPoint;
         private Bundle mExtras;
 
+        /**
+         * Default constructor.
+         *
+         * @param taskId of the type used by {@link android.app.ActivityManager}
+         */
         public Builder(int taskId) {
             mTaskId = taskId;
         }
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index a6abe0b..ddd5313 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -172,6 +172,15 @@
     public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
 
     /**
+     * The name of the assistant app role.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
+
+    /**
      * The action used to request user approval of a role for an application.
      *
      * @hide
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 17cf702..4d8dc35 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -532,6 +532,28 @@
             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
 
     /**
+     * Intent to broadcast silence mode changed.
+     * Alway contains the extra field {@link #EXTRA_DEVICE}
+     * Alway contains the extra field {@link #EXTRA_SILENCE_ENABLED}
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_SILENCE_MODE_CHANGED =
+            "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+
+    /**
+     * Used as an extra field in {@link #ACTION_SILENCE_MODE_CHANGED} intent,
+     * contains whether device is in silence mode as boolean.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SILENCE_ENABLED =
+            "android.bluetooth.device.extra.SILENCE_ENABLED";
+
+    /**
      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
      *
      * @hide
@@ -1592,6 +1614,70 @@
     }
 
     /**
+     * Set the Bluetooth device silence mode.
+     *
+     * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
+     * is an active device (for A2DP or HFP), the active device for that profile
+     * will be set to null.
+     * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
+     * active device is null, the {@link BluetoothDevice} will be set as the
+     * active device for that profile.
+     * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
+     * If the {@link BluetoothDevice} is set as the active device for A2DP or
+     * HFP, while silence mode is enabled, then the device will exit silence mode.
+     * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
+     * event and HFP AG indicators will be disabled.
+     * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
+     * enter silence mode.
+     *
+     * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @param silence true to enter silence mode, false to exit
+     * @return true on success, false on error.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setSilenceMode(boolean silence) {
+        final IBluetooth service = sService;
+        if (service == null) {
+            return false;
+        }
+        try {
+            if (getSilenceMode() == silence) {
+                return true;
+            }
+            return service.setSilenceMode(this, silence);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setSilenceMode fail", e);
+            return false;
+        }
+    }
+
+    /**
+     * Get the device silence mode status
+     *
+     * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @return true on device in silence mode, otherwise false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean getSilenceMode() {
+        final IBluetooth service = sService;
+        if (service == null) {
+            return false;
+        }
+        try {
+            return service.getSilenceMode(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getSilenceMode fail", e);
+            return false;
+        }
+    }
+
+    /**
      * Sets whether the phonebook access is allowed to this device.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
      *
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index c702b16..276853d 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -76,4 +76,6 @@
 
     // System API used by framework's ShareSheet (ChooserActivity)
     ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId);
+
+    boolean hasShareTargets(String packageName, String packageToCheck, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 4f7acd9..849fd03 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -635,4 +635,21 @@
                     }
                 };
     }
+
+    /**
+     * Used by framework's ShareSheet (ChooserActivity.java) to check if a given package has share
+     * target definitions in it's resources.
+     *
+     * @param packageName Package to check for share targets.
+     * @return True if the package has any share target definitions, False otherwise.
+     * @hide
+     */
+    public boolean hasShareTargets(@NonNull String packageName) {
+        try {
+            return mService.hasShareTargets(mContext.getPackageName(), packageName,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index ae5b003..27f0b04 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -23,12 +23,14 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.metrics.LogMaker;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.provider.Settings.Secure;
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
@@ -100,6 +102,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int AUTO_MODE_DISABLED = 0;
     /**
      * Auto mode value to automatically activate Night display at a specific start and end time.
@@ -110,6 +113,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int AUTO_MODE_CUSTOM_TIME = 1;
     /**
      * Auto mode value to automatically activate Night display from sunset to sunrise.
@@ -118,8 +122,45 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int AUTO_MODE_TWILIGHT = 2;
 
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED, COLOR_MODE_AUTOMATIC})
+    public @interface ColorMode {}
+
+    /**
+     * Color mode with natural colors.
+     *
+     * @hide
+     * @see #setColorMode(int)
+     */
+    public static final int COLOR_MODE_NATURAL = 0;
+    /**
+     * Color mode with boosted colors.
+     *
+     * @hide
+     * @see #setColorMode(int)
+     */
+    public static final int COLOR_MODE_BOOSTED = 1;
+    /**
+     * Color mode with saturated colors.
+     *
+     * @hide
+     * @see #setColorMode(int)
+     */
+    public static final int COLOR_MODE_SATURATED = 2;
+    /**
+     * Color mode with automatic colors.
+     *
+     * @hide
+     * @see #setColorMode(int)
+     */
+    public static final int COLOR_MODE_AUTOMATIC = 3;
+
     private final ColorDisplayManagerInternal mManager;
     private MetricsLogger mMetricsLogger;
 
@@ -175,6 +216,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public @AutoMode int getNightDisplayAutoMode() {
         return mManager.getNightDisplayAutoMode();
     }
@@ -199,6 +242,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public boolean setNightDisplayAutoMode(@AutoMode int autoMode) {
         if (autoMode != AUTO_MODE_DISABLED
                 && autoMode != AUTO_MODE_CUSTOM_TIME
@@ -233,6 +278,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public boolean setNightDisplayCustomStartTime(@NonNull LocalTime startTime) {
         if (startTime == null) {
             throw new IllegalArgumentException("startTime cannot be null");
@@ -263,6 +310,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public boolean setNightDisplayCustomEndTime(@NonNull LocalTime endTime) {
         if (endTime == null) {
             throw new IllegalArgumentException("endTime cannot be null");
@@ -275,6 +324,24 @@
     }
 
     /**
+     * Sets the current display color mode.
+     *
+     * @hide
+     */
+    public void setColorMode(int colorMode) {
+        mManager.setColorMode(colorMode);
+    }
+
+    /**
+     * Gets the current display color mode.
+     *
+     * @hide
+     */
+    public int getColorMode() {
+        return mManager.getColorMode();
+    }
+
+    /**
      * Returns whether the device has a wide color gamut display.
      *
      * @hide
@@ -373,6 +440,18 @@
         return mManager.getTransformCapabilities();
     }
 
+    /**
+     * Returns whether accessibility transforms are currently enabled, which determines whether
+     * color modes are currently configurable for this device.
+     *
+     * @hide
+     */
+    public static boolean areAccessibilityTransformsEnabled(Context context) {
+        final ContentResolver cr = context.getContentResolver();
+        return Secure.getInt(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0) == 1
+                || Secure.getInt(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0) == 1;
+    }
+
     private MetricsLogger getMetricsLogger() {
         if (mMetricsLogger == null) {
             mMetricsLogger = new MetricsLogger();
@@ -517,6 +596,22 @@
             }
         }
 
+        int getColorMode() {
+            try {
+                return mCdm.getColorMode();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        void setColorMode(int colorMode) {
+            try {
+                mCdm.setColorMode(colorMode);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         int getTransformCapabilities() {
             try {
                 return mCdm.getTransformCapabilities();
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index 1918fd5..30e76cf 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -38,4 +38,7 @@
     boolean setNightDisplayCustomStartTime(in Time time);
     Time getNightDisplayCustomEndTime();
     boolean setNightDisplayCustomEndTime(in Time time);
+
+    int getColorMode();
+    void setColorMode(int colorMode);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index a98b31a..56020b2 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
@@ -33,6 +34,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.List;
 
 /**
@@ -106,9 +109,24 @@
     public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
     public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
 
+    @IntDef ({
+        RESULT_SUCCESS,
+        RESULT_TIMEOUT,
+        RESULT_SOURCE_NOT_AVAILABLE,
+        RESULT_TARGET_NOT_AVAILABLE,
+        RESULT_ALREADY_IN_PROGRESS,
+        RESULT_EXCEPTION,
+        RESULT_INCORRECT_MODE,
+        RESULT_COMMUNICATION_FAILED,
+    })
+    public @interface ControlCallbackResult {}
+
+    /** Control operation is successfully handled by the framework. */
     public static final int RESULT_SUCCESS = 0;
     public static final int RESULT_TIMEOUT = 1;
+    /** Source device that the application is using is not available. */
     public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
+    /** Target device that the application is controlling is not available. */
     public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
 
     @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4;
@@ -394,16 +412,15 @@
     /**
      * Gets an object that represents an HDMI-CEC logical device of type switch on the system.
      *
-     * <p>Used to send HDMI control messages to other devices like TV through HDMI bus. It is also
-     * possible to communicate with other logical devices hosted in the same system if the system is
-     * configured to host more than one type of HDMI-CEC logical devices.
+     * <p>Used to send HDMI control messages to other devices (e.g. TVs) through HDMI bus.
+     * It is also possible to communicate with other logical devices hosted in the same
+     * system if the system is configured to host more than one type of HDMI-CEC logical device.
      *
      * @return {@link HdmiSwitchClient} instance. {@code null} on failure.
-     *
-     * TODO(b/110094868): unhide for Q
      * @hide
      */
     @Nullable
+    @SystemApi
     @SuppressLint("Doclava125")
     public HdmiSwitchClient getSwitchClient() {
         return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
@@ -412,11 +429,15 @@
     /**
      * Get a snapshot of the real-time status of the remote devices.
      *
-     * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
+     * <p>This only applies to devices with multiple HDMI inputs.
      *
-     * TODO(b/110094868): unhide for Q
+     * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices. An empty
+     * list will be returned if there is none.
+     *
      * @hide
      */
+    @SystemApi
+    @Nullable
     public List<HdmiDeviceInfo> getConnectedDevicesList() {
         try {
             return mService.getDeviceList();
@@ -426,14 +447,17 @@
     }
 
     /**
-     * Power off the target device.
+     * Power off the target device by sending CEC commands.
      *
-     * @param deviceInfo HdmiDeviceInfo of the device to be powered off
+     * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
      *
-     * TODO(b/110094868): unhide for Q
+     * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered off.
+     *
      * @hide
      */
+    @SystemApi
     public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        Preconditions.checkNotNull(deviceInfo);
         try {
             mService.powerOffRemoteDevice(
                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
@@ -443,14 +467,16 @@
     }
 
     /**
-     * Power on the target device.
+     * Power on the target device by sending CEC commands.
      *
-     * @param deviceInfo HdmiDeviceInfo of the device to be powered on
+     * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
      *
-     * TODO(b/110094868): unhide for Q
+     * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered on.
+     *
      * @hide
      */
     public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        Preconditions.checkNotNull(deviceInfo);
         try {
             mService.powerOnRemoteDevice(
                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
@@ -460,14 +486,17 @@
     }
 
     /**
-     * Ask the target device to be the new Active Source.
+     * Request the target device to be the new Active Source by sending CEC commands.
+     *
+     * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
      *
      * @param deviceInfo HdmiDeviceInfo of the target device
      *
-     * TODO(b/110094868): unhide for Q
      * @hide
      */
-    public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+    @SystemApi
+    public void requestRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+        Preconditions.checkNotNull(deviceInfo);
         try {
             mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
         } catch (RemoteException e) {
@@ -506,8 +535,13 @@
     /**
      * Get the physical address of the device.
      *
+     * <p>Physical address needs to be automatically adjusted when devices are phyiscally or
+     * electrically added or removed from the device tree. Please see HDMI Specification Version
+     * 1.4b 8.7 Physical Address for more details on the address discovery proccess.
+     *
      * @hide
      */
+    @SystemApi
     public int getPhysicalAddress() {
         if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
             return mPhysicalAddress;
@@ -521,16 +555,19 @@
     }
 
     /**
-     * Check if the target device is connected to the current device. The
-     * API also returns true if the current device is the target.
+     * Check if the target remote device is connected to the current device.
+     *
+     * <p>The API also returns true if the current device is the target.
      *
      * @param targetDevice {@link HdmiDeviceInfo} of the target device.
-     * @return true if {@code device} is directly or indirectly connected to the
+     * @return true if {@code targetDevice} is directly or indirectly
+     * connected to the current device.
      *
-     * TODO(b/110094868): unhide for Q
      * @hide
      */
-    public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+    @SystemApi
+    public boolean isRemoteDeviceConnected(HdmiDeviceInfo targetDevice) {
+        Preconditions.checkNotNull(targetDevice);
         mPhysicalAddress = getPhysicalAddress();
         if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
             return false;
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index 1ac2973..a036512 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -15,24 +15,30 @@
  */
 package android.hardware.hdmi;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.hdmi.HdmiControlManager.ControlCallbackResult;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
- * HdmiSwitchClient represents HDMI-CEC logical device of type Switch in the Android system which
- * acts as switch.
+ * An {@code HdmiSwitchClient} represents a HDMI-CEC switch device.
  *
- * <p>HdmiSwitchClient has a CEC device type of HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH,
- * but it is used by all Android TV devices that have multiple HDMI inputs,
- * even if it is not a "pure" swicth and has another device type like TV or Player.
+ * <p>HdmiSwitchClient has a CEC device type of HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH, but it is
+ * used by all Android devices that have multiple HDMI inputs, even if it is not a "pure" swicth
+ * and has another device type like TV or Player.
  *
  * @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
  */
+@SystemApi
 public class HdmiSwitchClient extends HdmiClient {
 
     private static final String TAG = "HdmiSwitchClient";
@@ -41,17 +47,15 @@
         super(service);
     }
 
-    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+    private static IHdmiControlCallback getCallbackWrapper(final OnSelectListener listener) {
         return new IHdmiControlCallback.Stub() {
             @Override
             public void onComplete(int result) {
-                callback.onComplete(result);
+                listener.onSelect(result);
             }
         };
     }
 
-    /** @hide */
-    // TODO(b/110094868): unhide for Q
     @Override
     public int getDeviceType() {
         return HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH;
@@ -61,20 +65,17 @@
      * Selects a CEC logical device to be a new active source.
      *
      * @param logicalAddress logical address of the device to select
-     * @param callback callback to get the result with
-     * @throws {@link IllegalArgumentException} if the {@code callback} is null
+     * @param listener listener to get the result with
      *
      * @hide
-     * TODO(b/110094868): unhide and add @SystemApi for Q
      */
-    public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null.");
-        }
+    public void selectDevice(int logicalAddress, @NonNull OnSelectListener listener) {
+        Preconditions.checkNotNull(listener);
         try {
-            mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+            mService.deviceSelect(logicalAddress, getCallbackWrapper(listener));
         } catch (RemoteException e) {
             Log.e(TAG, "failed to select device: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -82,20 +83,83 @@
      * Selects a HDMI port to be a new route path.
      *
      * @param portId HDMI port to select
-     * @param callback callback to get the result with
-     * @throws {@link IllegalArgumentException} if the {@code callback} is null
+     * @see {@link android.media.tv.TvInputHardwareInfo#getHdmiPortId()}
+     *     to get portId of a specific TV Input.
+     * @param listener listener to get the result with
      *
      * @hide
-     * TODO(b/110094868): unhide and add @SystemApi for Q
      */
-    public void portSelect(int portId, @NonNull SelectCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("Callback must not be null");
-        }
+    @SystemApi
+    public void selectPort(int portId, @NonNull OnSelectListener listener) {
+        Preconditions.checkNotNull(listener);
         try {
-            mService.portSelect(portId, getCallbackWrapper(callback));
+            mService.portSelect(portId, getCallbackWrapper(listener));
         } catch (RemoteException e) {
             Log.e(TAG, "failed to select port: ", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Selects a CEC logical device to be a new active source.
+     *
+     * @param logicalAddress logical address of the device to select
+     * @param executor executor to allow the develper to specify the thread upon which the listeners
+     *     will be invoked
+     * @param listener listener to get the result with
+     *
+     * @hide
+     */
+    public void selectDevice(
+            int logicalAddress,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnSelectListener listener) {
+        Preconditions.checkNotNull(listener);
+        try {
+            mService.deviceSelect(logicalAddress,
+                    new IHdmiControlCallback.Stub() {
+                            @Override
+                            public void onComplete(int result) {
+                                Binder.withCleanCallingIdentity(
+                                        () -> executor.execute(() -> listener.onSelect(result)));
+                            }
+                    }
+            );
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to select device: ", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Selects a HDMI port to be a new route path.
+     *
+     * @param portId HDMI port to select
+     * @param executor executor to allow the develper to specify the thread upon which the listeners
+     *     will be invoked
+     * @param listener listener to get the result with
+     *
+     * @hide
+     */
+    @SystemApi
+    public void selectPort(
+            int portId,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnSelectListener listener) {
+        Preconditions.checkNotNull(listener);
+        try {
+            mService.portSelect(portId,
+                    new IHdmiControlCallback.Stub() {
+                            @Override
+                            public void onComplete(int result) {
+                                Binder.withCleanCallingIdentity(
+                                        () -> executor.execute(() -> listener.onSelect(result)));
+                            }
+                    }
+            );
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to select port: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -105,10 +169,9 @@
      * <p>This only applies to device with multiple HDMI inputs
      *
      * @return list of {@link HdmiDeviceInfo} for connected CEC devices. Empty list is returned if
-     * there is none.
+     *     there is none.
      *
      * @hide
-     * TODO(b/110094868): unhide and add @SystemApi for Q
      */
     public List<HdmiDeviceInfo> getDeviceList() {
         try {
@@ -120,18 +183,19 @@
     }
 
     /**
-     * Callback interface used to get the result of {@link #deviceSelect} or {@link #portSelect}.
+     * Listener interface used to get the result of {@link #deviceSelect} or {@link #portSelect}.
      *
      * @hide
-     * TODO(b/110094868): unhide and add @SystemApi for Q
      */
-    public interface SelectCallback {
+    @SystemApi
+    public interface OnSelectListener {
 
         /**
          * Called when the operation is finished.
          *
-         * @param result the result value of {@link #deviceSelect} or {@link #portSelect}.
+         * @param result callback result.
+         * @see {@link ControlCallbackResult}
          */
-        void onComplete(int result);
+        void onSelect(@ControlCallbackResult int result);
     }
 }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 1030694..37b25c8 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -179,19 +179,24 @@
                 return;
             case DO_START_INPUT: {
                 final SomeArgs args = (SomeArgs) msg.obj;
-                final int missingMethods = msg.arg1;
-                final boolean restarting = msg.arg2 != 0;
                 final IBinder startInputToken = (IBinder) args.arg1;
                 final IInputContext inputContext = (IInputContext) args.arg2;
                 final EditorInfo info = (EditorInfo) args.arg3;
                 final AtomicBoolean isUnbindIssued = (AtomicBoolean) args.arg4;
+                SomeArgs moreArgs = (SomeArgs) args.arg5;
                 final InputConnection ic = inputContext != null
                         ? new InputConnectionWrapper(
-                                mTarget, inputContext, missingMethods, isUnbindIssued) : null;
+                                mTarget, inputContext, moreArgs.argi3, isUnbindIssued)
+                        : null;
                 info.makeCompatible(mTargetSdkVersion);
-                inputMethod.dispatchStartInputWithToken(ic, info, restarting /* restarting */,
-                        startInputToken);
+                inputMethod.dispatchStartInputWithToken(
+                        ic,
+                        info,
+                        moreArgs.argi1 == 1 /* restarting */,
+                        startInputToken,
+                        moreArgs.argi2 == 1 /* shouldPreRenderIme */);
                 args.recycle();
+                moreArgs.recycle();
                 return;
             }
             case DO_CREATE_SESSION: {
@@ -291,14 +296,17 @@
     @Override
     public void startInput(IBinder startInputToken, IInputContext inputContext,
             @InputConnectionInspector.MissingMethodFlags final int missingMethods,
-            EditorInfo attribute, boolean restarting) {
+            EditorInfo attribute, boolean restarting, boolean shouldPreRenderIme) {
         if (mIsUnbindIssued == null) {
             Log.e(TAG, "startInput must be called after bindInput.");
             mIsUnbindIssued = new AtomicBoolean();
         }
-        mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOOO(DO_START_INPUT,
-                missingMethods, restarting ? 1 : 0, startInputToken, inputContext, attribute,
-                mIsUnbindIssued));
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = restarting ? 1 : 0;
+        args.argi2 = shouldPreRenderIme ? 1 : 0;
+        args.argi3 = missingMethods;
+        mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOO(
+                DO_START_INPUT, startInputToken, inputContext, attribute, mIsUnbindIssued, args));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 38ddc16..5b3ad77 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,6 +346,13 @@
      */
     public static final int IME_VISIBLE = 0x2;
 
+    /**
+     * @hide
+     * The IME is active and ready with views but set invisible.
+     * This flag cannot be combined with {@link #IME_VISIBLE}.
+     */
+    public static final int IME_INVISIBLE = 0x4;
+
     // Min and max values for back disposition.
     private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
     private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
@@ -362,10 +369,19 @@
     View mRootView;
     SoftInputWindow mWindow;
     boolean mInitialized;
-    boolean mWindowCreated;
-    boolean mWindowVisible;
-    boolean mWindowWasVisible;
+    boolean mViewsCreated;
+    // IME views visibility.
+    boolean mDecorViewVisible;
+    boolean mDecorViewWasVisible;
     boolean mInShowWindow;
+    // True if pre-rendering of IME views/window is supported.
+    boolean mCanPreRender;
+    // If IME is pre-rendered.
+    boolean mIsPreRendered;
+    // IME window visibility.
+    // Use (mDecorViewVisible && mWindowVisible) to check if IME is visible to the user.
+    boolean mWindowVisible;
+
     ViewGroup mFullscreenArea;
     FrameLayout mExtractFrame;
     FrameLayout mCandidatesFrame;
@@ -552,15 +568,18 @@
          */
         @MainThread
         @Override
-        public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
+        public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
                 @NonNull EditorInfo editorInfo, boolean restarting,
-                @NonNull IBinder startInputToken) {
+                @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
             mPrivOps.reportStartInput(startInputToken);
-            // This needs to be dispatched to interface methods rather than doStartInput().
-            // Otherwise IME developers who have overridden those interface methods will lose
-            // notifications.
-            super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting,
-                    startInputToken);
+            mCanPreRender = shouldPreRenderIme;
+            if (DEBUG) Log.v(TAG, "Will Pre-render IME: " + mCanPreRender);
+
+            if (restarting) {
+                restartInput(inputConnection, editorInfo);
+            } else {
+                startInput(inputConnection, editorInfo);
+            }
         }
 
         /**
@@ -570,14 +589,27 @@
         @Override
         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
-            boolean wasVis = isInputViewShown();
-            mShowInputFlags = 0;
-            mShowInputRequested = false;
-            doHideWindow();
+            final boolean wasVisible = mIsPreRendered
+                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+            if (mIsPreRendered) {
+                // TODO: notify visibility to insets consumer.
+                if (DEBUG) {
+                    Log.v(TAG, "Making IME window invisible");
+                }
+                setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
+                onPreRenderedWindowVisibilityChanged(false /* setVisible */);
+            } else {
+                mShowInputFlags = 0;
+                mShowInputRequested = false;
+                doHideWindow();
+            }
+            final boolean isVisible = mIsPreRendered
+                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+            final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
-                resultReceiver.send(wasVis != isInputViewShown()
+                resultReceiver.send(visibilityChanged
                         ? InputMethodManager.RESULT_HIDDEN
-                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+                        : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                                 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
             }
         }
@@ -589,17 +621,28 @@
         @Override
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "showSoftInput()");
-            boolean wasVis = isInputViewShown();
+            final boolean wasVisible = mIsPreRendered
+                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
-                showWindow(true);
+                if (mIsPreRendered) {
+                    // TODO: notify visibility to insets consumer.
+                    if (DEBUG) {
+                        Log.v(TAG, "Making IME window visible");
+                    }
+                    onPreRenderedWindowVisibilityChanged(true /* setVisible */);
+                } else {
+                    showWindow(true);
+                }
             }
             // If user uses hard keyboard, IME button should always be shown.
-            setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
-
+            setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+            final boolean isVisible = mIsPreRendered
+                    ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+            final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
-                resultReceiver.send(wasVis != isInputViewShown()
+                resultReceiver.send(visibilityChanged
                         ? InputMethodManager.RESULT_SHOWN
-                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+                        : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
                                 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
             }
         }
@@ -972,7 +1015,7 @@
 
     void initViews() {
         mInitialized = false;
-        mWindowCreated = false;
+        mViewsCreated = false;
         mShowInputRequested = false;
         mShowInputFlags = 0;
 
@@ -1046,7 +1089,7 @@
     }
 
     private void resetStateForNewConfiguration() {
-        boolean visible = mWindowVisible;
+        boolean visible = mDecorViewVisible;
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
         CompletionInfo[] completions = mCurCompletions;
@@ -1129,7 +1172,7 @@
             return;
         }
         mBackDisposition = disposition;
-        setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
+        setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
     }
 
     /**
@@ -1380,7 +1423,7 @@
             mExtractFrame.setVisibility(View.GONE);
         }
         updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
-        if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
+        if (mDecorViewWasVisible && mFullscreenArea.getVisibility() != vis) {
             int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
                     ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
                     : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
@@ -1439,7 +1482,7 @@
      */
     public void updateInputViewShown() {
         boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
-        if (mIsInputViewShown != isShown && mWindowVisible) {
+        if (mIsInputViewShown != isShown && mDecorViewVisible) {
             mIsInputViewShown = isShown;
             mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
             if (mInputView == null) {
@@ -1458,14 +1501,14 @@
     public boolean isShowInputRequested() {
         return mShowInputRequested;
     }
-    
+
     /**
      * Return whether the soft input view is <em>currently</em> shown to the
      * user.  This is the state that was last determined and
      * applied by {@link #updateInputViewShown()}.
      */
     public boolean isInputViewShown() {
-        return mIsInputViewShown && mWindowVisible;
+        return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
     }
 
     /**
@@ -1499,7 +1542,7 @@
      */
     public void setCandidatesViewShown(boolean shown) {
         updateCandidatesVisibility(shown);
-        if (!mShowInputRequested && mWindowVisible != shown) {
+        if (!mShowInputRequested && mDecorViewVisible != shown) {
             // If we are being asked to show the candidates view while the app
             // has not asked for the input view to be shown, then we need
             // to update whether the window is shown.
@@ -1804,7 +1847,8 @@
     public void showWindow(boolean showInput) {
         if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                 + " mShowInputRequested=" + mShowInputRequested
-                + " mWindowCreated=" + mWindowCreated
+                + " mViewsCreated=" + mViewsCreated
+                + " mDecorViewVisible=" + mDecorViewVisible
                 + " mWindowVisible=" + mWindowVisible
                 + " mInputStarted=" + mInputStarted
                 + " mShowInputFlags=" + mShowInputFlags);
@@ -1814,18 +1858,42 @@
             return;
         }
 
-        mWindowWasVisible = mWindowVisible;
+        mDecorViewWasVisible = mDecorViewVisible;
         mInShowWindow = true;
-        showWindowInner(showInput);
-        mWindowWasVisible = true;
+        boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible;
+        final int previousImeWindowStatus =
+                (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
+                        ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
+        startViews(prepareWindow(showInput));
+        final int nextImeWindowStatus = mapToImeWindowStatus();
+        if (previousImeWindowStatus != nextImeWindowStatus) {
+            setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
+        }
+
+        // compute visibility
+        onWindowShown();
+        mIsPreRendered = mCanPreRender;
+        if (mIsPreRendered) {
+            onPreRenderedWindowVisibilityChanged(true /* setVisible */);
+        } else {
+            // Pre-rendering not supported.
+            if (DEBUG) Log.d(TAG, "No pre-rendering supported");
+            mWindowVisible = true;
+        }
+
+        // request draw for the IME surface.
+        // When IME is not pre-rendered, this will actually show the IME.
+        if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
+            if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
+            mWindow.show();
+        }
+        mDecorViewWasVisible = true;
         mInShowWindow = false;
     }
 
-    void showWindowInner(boolean showInput) {
+    private boolean prepareWindow(boolean showInput) {
         boolean doShowInput = false;
-        final int previousImeWindowStatus =
-                (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
-        mWindowVisible = true;
+        mDecorViewVisible = true;
         if (!mShowInputRequested && mInputStarted && showInput) {
             doShowInput = true;
             mShowInputRequested = true;
@@ -1836,8 +1904,8 @@
         updateFullscreenMode();
         updateInputViewShown();
 
-        if (!mWindowCreated) {
-            mWindowCreated = true;
+        if (!mViewsCreated) {
+            mViewsCreated = true;
             initialize();
             if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
             View v = onCreateCandidatesView();
@@ -1846,6 +1914,10 @@
                 setCandidatesView(v);
             }
         }
+        return doShowInput;
+    }
+
+    private void startViews(boolean doShowInput) {
         if (mShowInputRequested) {
             if (!mInputViewStarted) {
                 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
@@ -1857,29 +1929,26 @@
             mCandidatesViewStarted = true;
             onStartCandidatesView(mInputEditorInfo, false);
         }
-        
-        if (doShowInput) {
-            startExtractingText(false);
-        }
+        if (doShowInput) startExtractingText(false);
+    }
 
-        final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
-        if (previousImeWindowStatus != nextImeWindowStatus) {
-            setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
-        }
-        if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
-            if (DEBUG) Log.v(TAG, "showWindow: showing!");
+    private void onPreRenderedWindowVisibilityChanged(boolean setVisible) {
+        mWindowVisible = setVisible;
+        mShowInputFlags = setVisible ? mShowInputFlags : 0;
+        mShowInputRequested = setVisible;
+        mDecorViewVisible = setVisible;
+        if (setVisible) {
             onWindowShown();
-            mWindow.show();
         }
     }
 
-    private void finishViews() {
+    private void finishViews(boolean finishingInput) {
         if (mInputViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
-            onFinishInputView(false);
+            onFinishInputView(finishingInput);
         } else if (mCandidatesViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
-            onFinishCandidatesView(false);
+            onFinishCandidatesView(finishingInput);
         }
         mInputViewStarted = false;
         mCandidatesViewStarted = false;
@@ -1891,12 +1960,15 @@
     }
 
     public void hideWindow() {
-        finishViews();
-        if (mWindowVisible) {
+        if (DEBUG) Log.v(TAG, "CALL: hideWindow");
+        mIsPreRendered = false;
+        mWindowVisible = false;
+        finishViews(false /* finishingInput */);
+        if (mDecorViewVisible) {
             mWindow.hide();
-            mWindowVisible = false;
+            mDecorViewVisible = false;
             onWindowHidden();
-            mWindowWasVisible = false;
+            mDecorViewWasVisible = false;
         }
         updateFullscreenMode();
     }
@@ -1956,15 +2028,8 @@
     }
     
     void doFinishInput() {
-        if (mInputViewStarted) {
-            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
-            onFinishInputView(true);
-        } else if (mCandidatesViewStarted) {
-            if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
-            onFinishCandidatesView(true);
-        }
-        mInputViewStarted = false;
-        mCandidatesViewStarted = false;
+        if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
+        finishViews(true /* finishingInput */);
         if (mInputStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
             onFinishInput();
@@ -1984,7 +2049,7 @@
         initialize();
         if (DEBUG) Log.v(TAG, "CALL: onStartInput");
         onStartInput(attribute, restarting);
-        if (mWindowVisible) {
+        if (mDecorViewVisible) {
             if (mShowInputRequested) {
                 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
                 mInputViewStarted = true;
@@ -1995,6 +2060,31 @@
                 mCandidatesViewStarted = true;
                 onStartCandidatesView(mInputEditorInfo, restarting);
             }
+        } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) {
+            // Pre-render IME views and window when real EditorInfo is available.
+            // pre-render IME window and keep it invisible.
+            if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName);
+            if (mInShowWindow) {
+                Log.w(TAG, "Re-entrance in to showWindow");
+                return;
+            }
+
+            mDecorViewWasVisible = mDecorViewVisible;
+            mInShowWindow = true;
+            startViews(prepareWindow(true /* showInput */));
+
+            // compute visibility
+            mIsPreRendered = true;
+            onPreRenderedWindowVisibilityChanged(false /* setVisible */);
+
+            // request draw for the IME surface.
+            // When IME is not pre-rendered, this will actually show the IME.
+            if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
+            mWindow.show();
+            mDecorViewWasVisible = true;
+            mInShowWindow = false;
+        } else {
+            mIsPreRendered = false;
         }
     }
     
@@ -2153,7 +2243,7 @@
             // consume the back key.
             if (doIt) requestHideSelf(0);
             return true;
-        } else if (mWindowVisible) {
+        } else if (mDecorViewVisible) {
             if (mCandidatesVisibility == View.VISIBLE) {
                 // If we are showing candidates even if no input area, then
                 // hide them.
@@ -2180,7 +2270,6 @@
         return mExtractEditText;
     }
 
-
     /**
      * Called back when a {@link KeyEvent} is forwarded from the target application.
      *
@@ -2893,8 +2982,11 @@
         inputContentInfo.setUriToken(uriToken);
     }
 
-    private static int mapToImeWindowStatus(boolean isInputViewShown) {
-        return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
+    private int mapToImeWindowStatus() {
+        return IME_ACTIVE
+                | (isInputViewShown()
+                        ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE)
+                        : IME_VISIBLE) : 0);
     }
 
     /**
@@ -2904,9 +2996,10 @@
     @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         final Printer p = new PrintWriterPrinter(fout);
         p.println("Input method service state for " + this + ":");
-        p.println("  mWindowCreated=" + mWindowCreated);
-        p.println("  mWindowVisible=" + mWindowVisible
-                + " mWindowWasVisible=" + mWindowWasVisible
+        p.println("  mViewsCreated=" + mViewsCreated);
+        p.println("  mDecorViewVisible=" + mDecorViewVisible
+                + " mDecorViewWasVisible=" + mDecorViewWasVisible
+                + " mWindowVisible=" + mWindowVisible
                 + " mInShowWindow=" + mInShowWindow);
         p.println("  Configuration=" + getResources().getConfiguration());
         p.println("  mToken=" + mToken);
@@ -2926,6 +3019,8 @@
         
         p.println("  mShowInputRequested=" + mShowInputRequested
                 + " mLastShowInputRequested=" + mLastShowInputRequested
+                + " mCanPreRender=" + mCanPreRender
+                + " mIsPreRendered=" + mIsPreRendered
                 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
         p.println("  mCandidatesVisibility=" + mCandidatesVisibility
                 + " mFullscreenApplied=" + mFullscreenApplied
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 243b0eba..5bb24ba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1014,20 +1014,14 @@
      *                   to remove an existing always-on VPN configuration.
      * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
      *        {@code false} otherwise.
-     * @param lockdownWhitelist The list of packages that are allowed to access network directly
-     *         when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
-     *         this method must be called when a package that should be whitelisted is installed or
-     *         uninstalled.
      * @return {@code true} if the package is set as always-on VPN controller;
      *         {@code false} otherwise.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
-            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
+            boolean lockdownEnabled) {
         try {
-            return mService.setAlwaysOnVpnPackage(
-                    userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
+            return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1042,7 +1036,6 @@
      *         or {@code null} if none is set.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public String getAlwaysOnVpnPackageForUser(int userId) {
         try {
             return mService.getAlwaysOnVpnPackage(userId);
@@ -1052,36 +1045,6 @@
     }
 
     /**
-     * @return whether always-on VPN is in lockdown mode.
-     *
-     * @hide
-     **/
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public boolean isVpnLockdownEnabled(int userId) {
-        try {
-            return mService.isVpnLockdownEnabled(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-    }
-
-    /**
-     * @return the list of packages that are allowed to access network when always-on VPN is in
-     * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
-     *
-     * @hide
-     **/
-    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
-    public List<String> getVpnLockdownWhitelist(int userId) {
-        try {
-            return mService.getVpnLockdownWhitelist(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index fd7360f..e97060a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -125,11 +125,8 @@
 
     boolean updateLockdownVpn();
     boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
-    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
-            in List<String> lockdownWhitelist);
+    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown);
     String getAlwaysOnVpnPackage(int userId);
-    boolean isVpnLockdownEnabled(int userId);
-    List<String> getVpnLockdownWhitelist(int userId);
 
     int checkMobileProvisioning(int suggestedTimeOutMs);
 
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 518528d..d463b44 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -75,13 +75,25 @@
         int BUGREPORT_ERROR_USER_DENIED_CONSENT =
                 IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
 
+        /** The request to get user consent timed out. */
+        int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT =
+                IDumpstateListener.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT;
+
         /**
          * Called when taking bugreport resulted in an error.
          *
          * @param errorCode the error that occurred. Possible values are
          *     {@code BUGREPORT_ERROR_INVALID_INPUT},
          *     {@code BUGREPORT_ERROR_RUNTIME},
-         *     {@code BUGREPORT_ERROR_USER_DENIED_CONSENT}.
+         *     {@code BUGREPORT_ERROR_USER_DENIED_CONSENT},
+         *     {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT}.
+         *
+         * <p>If {@code BUGREPORT_ERROR_USER_DENIED_CONSENT} is passed, then the user did not
+         * consent to sharing the bugreport with the calling app.
+         *
+         * <p>If {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT} is passed, then the consent timed
+         * out, but the bugreport could be available in the internal directory of dumpstate for
+         * manual retrieval.
          */
         void onError(@BugreportErrorCode int errorCode);
 
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 5bf9095..efcad3e 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -369,26 +369,6 @@
     }
 
     /**
-     * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494
-     * True: Rules file was loaded.
-     * False: Rules file was *not* loaded.
-     */
-    private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) {
-        // b/121153494
-        // Skip APK rules file checking.
-        if (!DEBUG) {
-            Log.v(TAG, "Skipping loading the rules file.");
-            // Fill in some default values for now, so the loader can get an answer when it asks.
-            // Most importantly, we need to indicate which app we are init'ing and what the
-            // developer options for it are so we can turn on ANGLE if needed.
-            setAngleInfo(paths, packageName, devOptIn, null, 0, 0);
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
      * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
      * True: APK rules file was loaded.
      * False: APK rules file was *not* loaded.
@@ -425,16 +405,57 @@
     }
 
     /**
+     * Pull ANGLE whitelist from GlobalSettings and compare against current package
+     */
+    private boolean checkAngleWhitelist(Bundle bundle, String packageName) {
+        List<String> angleWhitelist =
+                getGlobalSettingsString(bundle,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+
+        return angleWhitelist.contains(packageName);
+    }
+
+    /**
      * Pass ANGLE details down to trigger enable logic
      */
     public void setupAngle(Context context, Bundle bundle, String packageName) {
-        String devOptIn = getDriverForPkg(bundle, packageName);
+        if (packageName.isEmpty()) {
+            Log.v(TAG, "No package name available yet, skipping ANGLE setup");
+            return;
+        }
 
+        String devOptIn = getDriverForPkg(bundle, packageName);
         if (DEBUG) {
             Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
                     + "set to: '" + devOptIn + "'");
         }
 
+        // We only need to check rules if the app is whitelisted or the developer has
+        // explicitly chosen something other than default driver.
+        //
+        // The whitelist will be generated by the ANGLE APK at both boot time and
+        // ANGLE update time. It will only include apps mentioned in the rules file.
+        //
+        // If the user has set the developer option to something other than default,
+        // we need to call setupAngleRulesApk() with the package name and the developer
+        // option value (native/angle/other). Then later when we are actually trying to
+        // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
+        // and can confidently answer yes/no based on the previously set developer
+        // option value.
+        boolean whitelisted = checkAngleWhitelist(bundle, packageName);
+        boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
+        boolean rulesCheck = (whitelisted || !defaulted);
+        if (!rulesCheck) {
+            return;
+        }
+
+        if (whitelisted) {
+            Log.v(TAG, "ANGLE whitelist includes " + packageName);
+        }
+        if (!defaulted) {
+            Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
+        }
+
         String anglePkgName = getAnglePackageName(context);
         if (anglePkgName.isEmpty()) {
             Log.e(TAG, "Failed to find ANGLE package.");
@@ -466,12 +487,6 @@
             return;
         }
 
-        // b/121153494
-        if (setupAngleRulesDebug(packageName, paths, devOptIn)) {
-            // We setup ANGLE with defaults, so we're done here.
-            return;
-        }
-
         if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
             // We setup ANGLE with rules from the APK, so we're done here.
             return;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 63912ec..630bd2e 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -54,6 +54,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.io.UncheckedIOException;
 import java.net.DatagramSocket;
 import java.net.Socket;
 import java.nio.ByteOrder;
@@ -393,26 +394,41 @@
      * @param socket The Socket whose FileDescriptor is used to create
      *               a new ParcelFileDescriptor.
      *
-     * @return A new ParcelFileDescriptor with the FileDescriptor of the
-     *         specified Socket.
+     * @return A new ParcelFileDescriptor with a duped copy of the
+     * FileDescriptor of the specified Socket.
+     *
+     * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
     public static ParcelFileDescriptor fromSocket(Socket socket) {
         FileDescriptor fd = socket.getFileDescriptor$();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        try {
+            return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
-     * Create a new ParcelFileDescriptor from the specified DatagramSocket.
+     * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
+     * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
+     * the DatagramSocket, so you must still close the DatagramSocket as well
+     * as the new ParcelFileDescriptor.
      *
      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
      *               to create a new ParcelFileDescriptor.
      *
-     * @return A new ParcelFileDescriptor with the FileDescriptor of the
-     *         specified DatagramSocket.
+     * @return A new ParcelFileDescriptor with a duped copy of the
+     * FileDescriptor of the specified Socket.
+     *
+     * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
         FileDescriptor fd = datagramSocket.getFileDescriptor$();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        try {
+            return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -542,7 +558,7 @@
         }
         file.deactivate();
         FileDescriptor fd = file.getFileDescriptor();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        return fd != null ? ParcelFileDescriptor.dup(fd) : null;
     }
 
     /**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index cd823a9..148dd91 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -181,6 +181,23 @@
         String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
     }
 
+    /**
+     * Namespace for storage-related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface Storage {
+        String NAMESPACE = "storage";
+
+        /**
+         * If {@code 1}, enables the isolated storage feature. If {@code -1},
+         * disables the isolated storage feature. If {@code 0}, uses the default
+         * value from the build system.
+         */
+        String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
+    }
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0a592d4..d840e3c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -59,6 +59,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.SQLException;
+import android.hardware.display.ColorDisplayManager;
 import android.location.LocationManager;
 import android.media.AudioFormat;
 import android.net.ConnectivityManager;
@@ -89,7 +90,6 @@
 import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.widget.ILockSettings;
 
 import java.io.IOException;
@@ -3239,8 +3239,8 @@
 
         private static final Validator DISPLAY_COLOR_MODE_VALIDATOR =
                 new SettingsValidators.InclusiveIntegerRangeValidator(
-                        ColorDisplayController.COLOR_MODE_NATURAL,
-                        ColorDisplayController.COLOR_MODE_AUTOMATIC);
+                        ColorDisplayManager.COLOR_MODE_NATURAL,
+                        ColorDisplayManager.COLOR_MODE_AUTOMATIC);
 
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
@@ -5800,16 +5800,6 @@
         public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown";
 
         /**
-         * Comma separated list of packages that are allowed to access the network when VPN is in
-         * lockdown mode but not running.
-         * @see #ALWAYS_ON_VPN_LOCKDOWN
-         *
-         * @hide
-         */
-        public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST =
-                "always_on_vpn_lockdown_whitelist";
-
-        /**
          * Whether applications can be installed for this user via the system's
          * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
          *
@@ -7812,6 +7802,9 @@
          * or an activity that handles ACTION_ASSIST, or empty which means using the default
          * handling.
          *
+         * <p>This should be set indirectly by setting the {@link
+         * android.app.role.RoleManager#ROLE_ASSISTANT assistant role}.
+         *
          * @hide
          */
         @UnsupportedAppUsage
@@ -8246,6 +8239,16 @@
         private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
+         * swipe).
+         *
+         * @hide
+         */
+        public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
+
+        private static final Validator NOTIFICATION_DISMISS_RTL_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Comma separated list of QS tiles that have been auto-added already.
          * @hide
          */
@@ -8547,6 +8550,7 @@
             ASSIST_GESTURE_WAKE_ENABLED,
             VR_DISPLAY_MODE,
             NOTIFICATION_BADGING,
+            NOTIFICATION_DISMISS_RTL,
             QS_AUTO_ADDED_TILES,
             SCREENSAVER_ENABLED,
             SCREENSAVER_COMPONENTS,
@@ -8709,6 +8713,7 @@
             VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
             VALIDATORS.put(VR_DISPLAY_MODE, VR_DISPLAY_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_BADGING, NOTIFICATION_BADGING_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_DISMISS_RTL, NOTIFICATION_DISMISS_RTL_VALIDATOR);
             VALIDATORS.put(QS_AUTO_ADDED_TILES, QS_AUTO_ADDED_TILES_VALIDATOR);
             VALIDATORS.put(SCREENSAVER_ENABLED, SCREENSAVER_ENABLED_VALIDATOR);
             VALIDATORS.put(SCREENSAVER_COMPONENTS, SCREENSAVER_COMPONENTS_VALIDATOR);
@@ -12148,6 +12153,13 @@
                 "angle_gl_driver_selection_values";
 
         /**
+         * List of package names that should check ANGLE rules
+         * @hide
+         */
+        public static final String GLOBAL_SETTINGS_ANGLE_WHITELIST =
+                "angle_whitelist";
+
+        /**
          * Game Update Package global preference for all Apps.
          * 0 = Default
          * 1 = All Apps use Game Update Package
@@ -13018,28 +13030,6 @@
                 "sms_access_restriction_enabled";
 
         /**
-         * If set to 1, an app must have the READ_PRIVILEGED_PHONE_STATE permission (or be a device
-         * / profile owner with the READ_PHONE_STATE permission) to access device identifiers.
-         *
-         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
-         *
-         * @hide
-         */
-        public static final String PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED =
-                "privileged_device_identifier_check_enabled";
-
-        /**
-         * If set to 1, an app that is targeting Q and does not meet the new requirements to access
-         * device identifiers will receive a SecurityException.
-         *
-         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
-         *
-         * @hide
-         */
-        public static final String PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED =
-                "privileged_device_identifier_target_q_behavior_enabled";
-
-        /**
          * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
          * permission check for 3P apps.
          *
@@ -13062,6 +13052,17 @@
                 "privileged_device_identifier_non_priv_check_relaxed";
 
         /**
+         * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
+         * permission check for preloaded privileged apps.
+         *
+         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+         *
+         * @hide
+         */
+        public static final String PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED =
+                "privileged_device_identifier_priv_check_relaxed";
+
+        /**
          * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
          * and restoring to lower version of platform API will be skipped.
          *
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 0edcb3d..2984ef6 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -53,9 +53,9 @@
         DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
         DEFAULT_FLAGS.put("settings_slice_injection", "false");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
-        DEFAULT_FLAGS.put("settings_wifi_dpp", "false");
-        DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "false");
-        DEFAULT_FLAGS.put("settings_wifi_sharing", "false");
+        DEFAULT_FLAGS.put("settings_wifi_dpp", "true");
+        DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
+        DEFAULT_FLAGS.put("settings_wifi_sharing", "true");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 529776e..a6af1a2 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,7 +16,10 @@
 
 package android.view;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.SIZE;
 import static android.view.WindowInsets.Type.indexOf;
 
 import android.annotation.IntDef;
@@ -124,9 +127,10 @@
             @Nullable @InsetSide SparseIntArray typeSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
         Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
+        boolean[] typeVisibilityMap = new boolean[SIZE];
         final Rect relativeFrame = new Rect(frame);
         final Rect relativeFrameMax = new Rect(frame);
-        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_IME
+        if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
                 && legacyContentInsets != null && legacyStableInsets != null) {
             WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets);
             WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets);
@@ -136,22 +140,29 @@
             if (source == null) {
                 continue;
             }
+            if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
+                    && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR)) {
+                typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
+                continue;
+            }
+
             processSource(source, relativeFrame, false /* ignoreVisibility */, typeInsetsMap,
-                    typeSideMap);
+                    typeSideMap, typeVisibilityMap);
 
             // IME won't be reported in max insets as the size depends on the EditorInfo of the IME
             // target.
             if (source.getType() != TYPE_IME) {
                 processSource(source, relativeFrameMax, true /* ignoreVisibility */,
-                        typeMaxInsetsMap, null /* typeSideMap */);
+                        typeMaxInsetsMap, null /* typeSideMap */, null /* typeVisibilityMap */);
             }
         }
-        return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, isScreenRound,
+        return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
                 alwaysConsumeNavBar, cutout);
     }
 
     private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
-            Insets[] typeInsetsMap, @Nullable @InsetSide SparseIntArray typeSideMap) {
+            Insets[] typeInsetsMap, @Nullable @InsetSide SparseIntArray typeSideMap,
+            @Nullable boolean[] typeVisibilityMap) {
         Insets insets = source.calculateInsets(relativeFrame, ignoreVisibility);
 
         int index = indexOf(toPublicType(source.getType()));
@@ -162,6 +173,10 @@
             typeInsetsMap[index] = Insets.max(existing, insets);
         }
 
+        if (typeVisibilityMap != null) {
+            typeVisibilityMap[index] = source.isVisible();
+        }
+
         if (typeSideMap != null && !Insets.NONE.equals(insets)) {
             @InsetSide int insetSide = getInsetSide(insets);
             if (insetSide != INSET_SIDE_UNKNWON) {
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index 3c9ce78..6f5a85d 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -18,7 +18,6 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityOptions;
-import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -52,6 +51,7 @@
     private final IRemoteAnimationRunner mRunner;
     private final long mDuration;
     private final long mStatusBarTransitionDelay;
+    private final boolean mChangeNeedsSnapshot;
 
     /** @see #getCallingPid */
     private int mCallingPid;
@@ -59,21 +59,31 @@
     /**
      * @param runner The interface that gets notified when we actually need to start the animation.
      * @param duration The duration of the animation.
+     * @param changeNeedsSnapshot For change transitions, whether this should create a snapshot by
+     *                            screenshotting the task.
      * @param statusBarTransitionDelay The desired delay for all visual animations in the
      *        status bar caused by this app animation in millis.
      */
     @UnsupportedAppUsage
     public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration,
-            long statusBarTransitionDelay) {
+            long statusBarTransitionDelay, boolean changeNeedsSnapshot) {
         mRunner = runner;
         mDuration = duration;
+        mChangeNeedsSnapshot = changeNeedsSnapshot;
         mStatusBarTransitionDelay = statusBarTransitionDelay;
     }
 
+    @UnsupportedAppUsage
+    public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration,
+            long statusBarTransitionDelay) {
+        this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */);
+    }
+
     public RemoteAnimationAdapter(Parcel in) {
         mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder());
         mDuration = in.readLong();
         mStatusBarTransitionDelay = in.readLong();
+        mChangeNeedsSnapshot = in.readBoolean();
     }
 
     public IRemoteAnimationRunner getRunner() {
@@ -88,6 +98,10 @@
         return mStatusBarTransitionDelay;
     }
 
+    public boolean getChangeNeedsSnapshot() {
+        return mChangeNeedsSnapshot;
+    }
+
     /**
      * To be called by system_server to keep track which pid is running this animation.
      */
@@ -112,6 +126,7 @@
         dest.writeStrongInterface(mRunner);
         dest.writeLong(mDuration);
         dest.writeLong(mStatusBarTransitionDelay);
+        dest.writeBoolean(mChangeNeedsSnapshot);
     }
 
     public static final Creator<RemoteAnimationAdapter> CREATOR
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 483280e..f1dfc1c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3985,6 +3985,15 @@
     public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
 
     /**
+     * If a MotionEvent has CLASSIFICATION_AMBIGUOUS_GESTURE set, then certain the default
+     * long press action will be inhibited. However, to account for the possibility of incorrect
+     * classification, the default long press timeout will instead be increased for some situations
+     * by the following factor.
+     * Likewise, the touch slop for allowing long press will be increased when gesture is uncertain.
+     */
+    private static final int AMBIGUOUS_GESTURE_MULTIPLIER = 2;
+
+    /**
      * Controls the over-scroll mode for this view.
      * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
      * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -9154,7 +9163,7 @@
 
         ContentCaptureSession session = null;
         if (mParent instanceof View) {
-            session = ((View) mParent).getContentCaptureSession();
+            session = ((View) mParent).getContentCaptureSession(ccm);
         }
 
         return session != null ? session : ccm.getMainContentCaptureSession();
@@ -14780,8 +14789,27 @@
                         drawableHotspotChanged(x, y);
                     }
 
+                    final int motionClassification = event.getClassification();
+                    final boolean ambiguousGesture =
+                            motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE;
+                    int touchSlop = mTouchSlop;
+                    if (ambiguousGesture && hasPendingLongPressCallback()) {
+                        if (!pointInView(x, y, touchSlop)) {
+                            // The default action here is to cancel long press. But instead, we
+                            // just extend the timeout here, in case the classification
+                            // stays ambiguous.
+                            removeLongPressCallback();
+                            long delay = ViewConfiguration.getLongPressTimeout()
+                                    * AMBIGUOUS_GESTURE_MULTIPLIER;
+                            // Subtract the time already spent
+                            delay -= event.getEventTime() - event.getDownTime();
+                            checkForLongClick(delay, x, y);
+                        }
+                        touchSlop *= AMBIGUOUS_GESTURE_MULTIPLIER;
+                    }
+
                     // Be lenient about moving outside of buttons
-                    if (!pointInView(x, y, mTouchSlop)) {
+                    if (!pointInView(x, y, touchSlop)) {
                         // Outside button
                         // Remove any future long press/tap checks
                         removeTapCallback();
@@ -14791,6 +14819,15 @@
                         }
                         mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                     }
+
+                    final boolean deepPress =
+                            motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS;
+                    if (deepPress && hasPendingLongPressCallback()) {
+                        // process the long click action immediately
+                        removeLongPressCallback();
+                        checkForLongClick(0 /* send immediately */, x, y);
+                    }
+
                     break;
             }
 
@@ -14825,6 +14862,21 @@
     }
 
     /**
+     * Return true if the long press callback is scheduled to run sometime in the future.
+     * Return false if there is no scheduled long press callback at the moment.
+     */
+    private boolean hasPendingLongPressCallback() {
+        if (mPendingCheckForLongPress == null) {
+            return false;
+        }
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo == null) {
+            return false;
+        }
+        return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress);
+    }
+
+   /**
      * Remove the pending click action
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index e808830..c1536ae 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -66,6 +66,7 @@
 
     private final Insets[] mTypeInsetsMap;
     private final Insets[] mTypeMaxInsetsMap;
+    private final boolean[] mTypeVisibilityMap;
 
     @Nullable private Rect mTempRect;
     private final boolean mIsRound;
@@ -106,6 +107,7 @@
     public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
             boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
         this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
+                createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
                 isRound, alwaysConsumeNavBar, displayCutout);
     }
 
@@ -122,7 +124,9 @@
      * @hide
      */
     public WindowInsets(@Nullable Insets[] typeInsetsMap,
-            @Nullable Insets[] typeMaxInsetsMap, boolean isRound,
+            @Nullable Insets[] typeMaxInsetsMap,
+            boolean[] typeVisibilityMap,
+            boolean isRound,
             boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
         mSystemWindowInsetsConsumed = typeInsetsMap == null;
         mTypeInsetsMap = mSystemWindowInsetsConsumed
@@ -134,6 +138,7 @@
                 ? new Insets[SIZE]
                 : typeMaxInsetsMap.clone();
 
+        mTypeVisibilityMap = typeVisibilityMap;
         mIsRound = isRound;
         mAlwaysConsumeNavBar = alwaysConsumeNavBar;
 
@@ -148,8 +153,8 @@
      * @param src Source to copy insets from
      */
     public WindowInsets(WindowInsets src) {
-        this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mIsRound, src.mAlwaysConsumeNavBar,
-                displayCutoutCopyConstructorArgument(src));
+        this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mTypeVisibilityMap, src.mIsRound,
+                src.mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(src));
     }
 
     private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
@@ -200,7 +205,7 @@
     /** @hide */
     @UnsupportedAppUsage
     public WindowInsets(Rect systemWindowInsets) {
-        this(createCompatTypeMap(systemWindowInsets), null, false, false, null);
+        this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
     }
 
     /**
@@ -225,6 +230,20 @@
         typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
     }
 
+    private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
+        boolean[] typeVisibilityMap = new boolean[SIZE];
+        if (typeInsetMap == null) {
+            return typeVisibilityMap;
+        }
+        for (int i = FIRST; i <= LAST; i = i << 1) {
+            int index = indexOf(i);
+            if (!Insets.NONE.equals(typeInsetMap[index])) {
+                typeVisibilityMap[index] = true;
+            }
+        }
+        return typeVisibilityMap;
+    }
+
     /**
      * Used to provide a safe copy of the system window insets to pass through
      * to the existing fitSystemWindows method and other similar internals.
@@ -297,6 +316,27 @@
     }
 
     /**
+     * Returns whether a set of windows that may cause insets is currently visible on screen,
+     * regardless of whether it actually overlaps with this window.
+     *
+     * @param typeMask Bit mask of {@link InsetType}s to query visibility status.
+     * @return {@code true} if and only if all windows included in {@code typeMask} are currently
+     *         visible on screen.
+     * @hide pending unhide
+     */
+    public boolean isVisible(@InsetType int typeMask) {
+        for (int i = FIRST; i <= LAST; i = i << 1) {
+            if ((typeMask & i) == 0) {
+                continue;
+            }
+            if (!mTypeVisibilityMap[indexOf(i)]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns the left system window inset in pixels.
      *
      * <p>The system window inset represents the area of a full-screen window that is
@@ -392,6 +432,7 @@
     public WindowInsets consumeDisplayCutout() {
         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
+                mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeNavBar,
                 null /* displayCutout */);
     }
@@ -437,6 +478,7 @@
     @NonNull
     public WindowInsets consumeSystemWindowInsets() {
         return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
+                mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeNavBar,
                 displayCutoutCopyConstructorArgument(this));
     }
@@ -594,7 +636,7 @@
     @NonNull
     public WindowInsets consumeStableInsets() {
         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
-                mIsRound, mAlwaysConsumeNavBar,
+                mTypeVisibilityMap, mIsRound, mAlwaysConsumeNavBar,
                 displayCutoutCopyConstructorArgument(this));
     }
 
@@ -671,6 +713,7 @@
                 mStableInsetsConsumed
                         ? null
                         : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
+                mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeNavBar,
                 mDisplayCutoutConsumed
                         ? null
@@ -692,14 +735,15 @@
                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
                 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
                 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
+                && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
                 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
-                mIsRound, mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
-                mStableInsetsConsumed, mDisplayCutoutConsumed);
+                Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mAlwaysConsumeNavBar,
+                mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
     }
 
 
@@ -754,6 +798,7 @@
 
         private final Insets[] mTypeInsetsMap;
         private final Insets[] mTypeMaxInsetsMap;
+        private final boolean[] mTypeVisibilityMap;
         private boolean mSystemInsetsConsumed = true;
         private boolean mStableInsetsConsumed = true;
 
@@ -768,6 +813,7 @@
         public Builder() {
             mTypeInsetsMap = new Insets[SIZE];
             mTypeMaxInsetsMap = new Insets[SIZE];
+            mTypeVisibilityMap = new boolean[SIZE];
         }
 
         /**
@@ -778,6 +824,7 @@
         public Builder(WindowInsets insets) {
             mTypeInsetsMap = insets.mTypeInsetsMap.clone();
             mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
+            mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
             mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
             mStableInsetsConsumed = insets.mStableInsetsConsumed;
             mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
@@ -862,6 +909,29 @@
         }
 
         /**
+         * Sets whether windows that can cause insets are currently visible on screen.
+         *
+         *
+         * @see #isVisible(int)
+         *
+         * @param typeMask The bitmask of {@link InsetType} to set the visibility for.
+         * @param visible Whether to mark the windows as visible or not.
+         *
+         * @return itself
+         * @hide pending unhide
+         */
+        @NonNull
+        public Builder setVisible(@InsetType int typeMask, boolean visible) {
+            for (int i = FIRST; i <= LAST; i = i << 1) {
+                if ((typeMask & i) == 0) {
+                    continue;
+                }
+                mTypeVisibilityMap[indexOf(i)] = visible;
+            }
+            return this;
+        }
+
+        /**
          * Sets the stable insets in pixels.
          *
          * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
@@ -916,8 +986,8 @@
         @NonNull
         public WindowInsets build() {
             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
-                    mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mIsRound,
-                    mAlwaysConsumeNavBar, mDisplayCutout);
+                    mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
+                    mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
         }
     }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 6ed2d80..c425e7b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -34,8 +34,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
-import dalvik.system.CloseGuard;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -148,9 +146,6 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface FlushReason{}
 
-
-    private final CloseGuard mCloseGuard = CloseGuard.get();
-
     private final Object mLock = new Object();
 
     /**
@@ -185,7 +180,6 @@
     @VisibleForTesting
     public ContentCaptureSession(@NonNull String id) {
         mId = Preconditions.checkNotNull(id);
-        mCloseGuard.open("destroy");
     }
 
     /** @hide */
@@ -251,8 +245,6 @@
             }
             mDestroyed = true;
 
-            mCloseGuard.close();
-
             // TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
             // id) and send it to the cache of batched commands
             if (VERBOSE) {
@@ -288,18 +280,6 @@
         destroy();
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            destroy();
-        } finally {
-            super.finalize();
-        }
-    }
-
     /**
      * Notifies the Content Capture Service that a node has been added to the view structure.
      *
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index d09323d..112653a 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -219,7 +219,7 @@
     @MainThread
     default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
             @NonNull EditorInfo editorInfo, boolean restarting,
-            @NonNull IBinder startInputToken) {
+            @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
         if (restarting) {
             restartInput(inputConnection, editorInfo);
         } else {
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 77cb4cd..fdc34b3 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -103,10 +103,9 @@
         final String modelName = String.format(
                 Locale.US, "%s_v%d", localesJoiner.toString(), modelVersion);
         final int hash = Objects.hash(
-                messages.stream()
-                        .map(ConversationActions.Message::getText)
-                        .collect(Collectors.toList()),
-                context.getPackageName());
+                messages.stream().mapToInt(ActionsSuggestionsHelper::hashMessage),
+                context.getPackageName(),
+                System.currentTimeMillis());
         return SelectionSessionLogger.SignatureParser.createSignature(
                 SelectionSessionLogger.CLASSIFIER_ID, modelName, hash);
     }
@@ -128,4 +127,8 @@
             return result;
         }
     }
+
+    private static int hashMessage(ConversationActions.Message message) {
+        return Objects.hash(message.getAuthor(), message.getText(), message.getReferenceTime());
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index ed86206..10c7ade 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -73,9 +73,16 @@
     /**
      * Returns the text classifier that was set via {@link #setTextClassifier(TextClassifier)}.
      * If this is null, this method returns a default text classifier (i.e. either the system text
-     * classifier if one exists, or a local text classifier running in this app.)
+     * classifier if one exists, or a local text classifier running in this process.)
+     * <p>
+     * Note that if system textclassifier is in use, requests will be sent to a textclassifier
+     * package provided from OEM. If you want to make sure the requests are handled in your own
+     * process, you should consider {@link #getLocalTextClassifier()} instead. However, the local
+     * textclassifier may return inferior results to those returned by the system
+     * textclassifier.
      *
      * @see #setTextClassifier(TextClassifier)
+     * @see #getLocalTextClassifier()
      */
     @NonNull
     public TextClassifier getTextClassifier() {
@@ -215,7 +222,13 @@
         return TextClassifier.NO_OP;
     }
 
-    private TextClassifier getLocalTextClassifier() {
+    /**
+     * Returns a local textclassifier, which is running in this process.
+     *
+     * @see #getTextClassifier()
+     */
+    @NonNull
+    public TextClassifier getLocalTextClassifier() {
         synchronized (mLock) {
             if (mLocalTextClassifier == null) {
                 if (getSettings().isLocalTextClassifierEnabled()) {
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index b84f6f0..cd13cc0 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -72,7 +72,7 @@
              TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
              TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
              TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
-             TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY})
+             TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED})
     public @interface Type {
         // For custom event types, use range 1,000,000+.
     }
@@ -121,7 +121,7 @@
 
     @Category private final int mEventCategory;
     @Type private final int mEventType;
-    @Nullable private final String mEntityType;
+    @Nullable private final String[] mEntityTypes;
     @Nullable private final TextClassificationContext mEventContext;
     @Nullable private final String mResultId;
     private final int mEventIndex;
@@ -139,11 +139,12 @@
 
     // Language detection.
     @Nullable private final String mLanguage;
+    private final float mScore;
 
     private TextClassifierEvent(
             int eventCategory,
             int eventType,
-            String entityType,
+            String[] entityTypes,
             TextClassificationContext eventContext,
             String resultId,
             int eventIndex,
@@ -154,10 +155,11 @@
             int relativeSuggestedWordStartIndex,
             int relativeSuggestedWordEndIndex,
             int[] actionIndex,
-            String language) {
+            String language,
+            float score) {
         mEventCategory = eventCategory;
         mEventType = eventType;
-        mEntityType = entityType;
+        mEntityTypes = entityTypes;
         mEventContext = eventContext;
         mResultId = resultId;
         mEventIndex = eventIndex;
@@ -169,6 +171,7 @@
         mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex;
         mActionIndices = actionIndex;
         mLanguage = language;
+        mScore = score;
     }
 
     @Override
@@ -180,7 +183,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mEventCategory);
         dest.writeInt(mEventType);
-        dest.writeString(mEntityType);
+        dest.writeStringArray(mEntityTypes);
         dest.writeParcelable(mEventContext, flags);
         dest.writeString(mResultId);
         dest.writeInt(mEventIndex);
@@ -192,13 +195,14 @@
         dest.writeInt(mRelativeSuggestedWordEndIndex);
         dest.writeIntArray(mActionIndices);
         dest.writeString(mLanguage);
+        dest.writeFloat(mScore);
     }
 
     private static TextClassifierEvent readFromParcel(Parcel in) {
         return new TextClassifierEvent(
                 /* eventCategory= */ in.readInt(),
                 /* eventType= */ in.readInt(),
-                /* entityType= */ in.readString(),
+                /* entityTypes=*/ in.readStringArray(),
                 /* eventContext= */ in.readParcelable(null),
                 /* resultId= */ in.readString(),
                 /* eventIndex= */ in.readInt(),
@@ -209,7 +213,8 @@
                 /* relativeSuggestedWordStartIndex= */ in.readInt(),
                 /* relativeSuggestedWordEndIndex= */ in.readInt(),
                 /* actionIndices= */ in.createIntArray(),
-                /* language= */ in.readString());
+                /* language= */ in.readString(),
+                /* score= */ in.readFloat());
     }
 
     /**
@@ -229,11 +234,11 @@
     }
 
     /**
-     * Returns the entity type. e.g. {@link TextClassifier#TYPE_ADDRESS}.
+     * Returns an array of entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
      */
-    @Nullable
-    public String getEntityType() {
-        return mEntityType;
+    @NonNull
+    public String[] getEntityTypes() {
+        return mEntityTypes;
     }
 
     /**
@@ -327,13 +332,20 @@
     }
 
     /**
+     * Returns the score of the suggestion.
+     */
+    public float getScore() {
+        return mScore;
+    }
+
+    /**
      * Builder to build a text classifier event.
      */
     public static final class Builder {
 
         private final int mEventCategory;
         private final int mEventType;
-        @Nullable private String mEntityType;
+        private String[] mEntityTypes = new String[0];
         @Nullable private TextClassificationContext mEventContext;
         @Nullable private String mResultId;
         private int mEventIndex;
@@ -345,6 +357,7 @@
         private int mRelativeSuggestedWordEndIndex;
         private int[] mActionIndices = new int[0];
         @Nullable private String mLanguage;
+        private float mScore;
 
         /**
          * Creates a builder for building {@link TextClassifierEvent}s.
@@ -358,11 +371,12 @@
         }
 
         /**
-         * Sets the entity type. e.g. {@link TextClassifier#TYPE_ADDRESS}.
+         * Sets the entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
          */
         @NonNull
-        public Builder setEntityType(@Nullable String entityType) {
-            mEntityType = entityType;
+        public Builder setEntityTypes(@NonNull String... entityTypes) {
+            mEntityTypes = new String[entityTypes.length];
+            System.arraycopy(entityTypes, 0, mEntityTypes, 0, entityTypes.length);
             return this;
         }
 
@@ -478,6 +492,15 @@
         }
 
         /**
+         * Sets the score of the suggestion.
+         */
+        @NonNull
+        public Builder setScore(float score) {
+            mScore = score;
+            return this;
+        }
+
+        /**
          * Builds and returns a text classifier event.
          */
         @NonNull
@@ -486,7 +509,7 @@
             return new TextClassifierEvent(
                     mEventCategory,
                     mEventType,
-                    mEntityType,
+                    mEntityTypes,
                     mEventContext,
                     mResultId,
                     mEventIndex,
@@ -497,7 +520,8 @@
                     mRelativeSuggestedWordStartIndex,
                     mRelativeSuggestedWordEndIndex,
                     mActionIndices,
-                    mLanguage);
+                    mLanguage,
+                    mScore);
         }
         // TODO: Add build(boolean validate).
     }
@@ -507,7 +531,7 @@
         StringBuilder out = new StringBuilder(128);
         out.append("TextClassifierEvent{");
         out.append("mEventCategory=").append(mEventCategory);
-        out.append(", mEventType=").append(mEventType);
+        out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes));
         out.append(", mEventContext=").append(mEventContext);
         out.append(", mResultId=").append(mResultId);
         out.append(", mEventIndex=").append(mEventIndex);
@@ -519,6 +543,7 @@
         out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex);
         out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
         out.append(", mLanguage=").append(mLanguage);
+        out.append(", mScore=").append(mScore);
         out.append("}");
         return out.toString();
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
index 439e594..5563dfc 100644
--- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
+++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
@@ -15,12 +15,15 @@
  */
 package android.view.textclassifier;
 
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_SESSION_ID;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SESSION_ID;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_VERSION;
 
 import android.metrics.LogMaker;
 
@@ -60,16 +63,30 @@
             return;
         }
         final LogMaker log = new LogMaker(category)
-                .setType(getLogType(event))
-                .addTaggedData(FIELD_SELECTION_SESSION_ID, event.getResultId())
+                .setSubtype(getLogType(event))
+                .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId())
                 .addTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME, event.getEventTime())
                 .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL,
                         SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()))
-                .addTaggedData(FIELD_SELECTION_ENTITY_TYPE, event.getEntityType());
+                .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore());
+
+        String[] entityTypes = event.getEntityTypes();
+        // TRON does not support a field of list type, and thus workaround by store them
+        // in three separate fields. This is no longer an issue once we have moved to Westworld.
+        if (entityTypes.length >= 1) {
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE, entityTypes[0]);
+        }
+        if (entityTypes.length >= 2) {
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE, entityTypes[1]);
+        }
+        if (entityTypes.length >= 3) {
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE, entityTypes[2]);
+        }
         TextClassificationContext eventContext = event.getEventContext();
         if (eventContext != null) {
-            log.addTaggedData(FIELD_SELECTION_WIDGET_TYPE, eventContext.getWidgetType());
-            log.addTaggedData(FIELD_SELECTION_WIDGET_VERSION, eventContext.getWidgetVersion());
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE, eventContext.getWidgetType());
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION,
+                    eventContext.getWidgetVersion());
             log.setPackageName(eventContext.getPackageName());
         }
         mMetricsLogger.write(log);
@@ -94,6 +111,8 @@
                 return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN;
             case TextClassifierEvent.TYPE_MANUAL_REPLY:
                 return MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY;
+            case TextClassifierEvent.TYPE_ACTIONS_GENERATED:
+                return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED;
             default:
                 return MetricsEvent.VIEW_UNKNOWN;
         }
@@ -127,14 +146,22 @@
         if (!Log.ENABLE_FULL_LOGGING) {
             return;
         }
-        final String id = String.valueOf(log.getTaggedData(FIELD_SELECTION_SESSION_ID));
+        final String id = String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID));
         final String categoryName = toCategoryName(log.getCategory());
-        final String eventName = toEventName(log.getType());
-        final String widgetType = String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_TYPE));
+        final String eventName = toEventName(log.getSubtype());
+        final String widgetType =
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE));
         final String widgetVersion =
-                String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_VERSION));
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION));
         final String model = String.valueOf(log.getTaggedData(FIELD_TEXTCLASSIFIER_MODEL));
-        final String entityType = String.valueOf(log.getTaggedData(FIELD_SELECTION_ENTITY_TYPE));
+        final String firstEntityType =
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE));
+        final String secondEntityType =
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE));
+        final String thirdEntityType =
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE));
+        final String score =
+                String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE));
 
         StringBuilder builder = new StringBuilder();
         builder.append("writeEvent: ");
@@ -144,7 +171,10 @@
         builder.append(", widgetType=").append(widgetType);
         builder.append(", widgetVersion=").append(widgetVersion);
         builder.append(", model=").append(model);
-        builder.append(", entityType=").append(entityType);
+        builder.append(", firstEntityType=").append(firstEntityType);
+        builder.append(", secondEntityType=").append(secondEntityType);
+        builder.append(", thirdEntityType=").append(thirdEntityType);
+        builder.append(", score=").append(score);
 
         Log.v(TAG, builder.toString());
     }
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 7c371cb..d0102a7 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -17,13 +17,10 @@
 package com.android.internal.app;
 
 import android.annotation.NonNull;
-import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,8 +28,6 @@
 import android.provider.Settings;
 import android.util.Log;
 
-import com.android.internal.R;
-
 import java.util.ArrayList;
 import java.util.Set;
 
@@ -44,14 +39,6 @@
 
     private static final String TAG = "AssistUtils";
 
-    /**
-     * Sentinel value for "no default assistant specified."
-     *
-     * Empty string is already used to represent an explicit setting of No Assistant. null cannot
-     * be used because we can't represent a null value in XML.
-     */
-    private static final String UNSET = "#+UNSET";
-
     private final Context mContext;
     private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
 
@@ -186,37 +173,9 @@
                 Settings.Secure.ASSISTANT, userId);
         if (setting != null) {
             return ComponentName.unflattenFromString(setting);
-        }
-
-        final String defaultSetting = mContext.getResources().getString(
-                R.string.config_defaultAssistantComponentName);
-        if (defaultSetting != null && !defaultSetting.equals(UNSET)) {
-            return ComponentName.unflattenFromString(defaultSetting);
-        }
-
-        // Fallback to keep backward compatible behavior when there is no user setting.
-        if (activeServiceSupportsAssistGesture()) {
-            return getActiveServiceComponentName();
-        }
-
-        if (UNSET.equals(defaultSetting)) {
+        } else {
             return null;
         }
-
-        final SearchManager searchManager =
-                (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        if (searchManager == null) {
-            return null;
-        }
-        final Intent intent = searchManager.getAssistIntent(false);
-        PackageManager pm = mContext.getPackageManager();
-        ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY,
-                userId);
-        if (info != null) {
-            return new ComponentName(info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-        }
-        return null;
     }
 
     public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 30137e38..42acb09 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -513,6 +513,7 @@
 
     void queryTargetServices(ChooserListAdapter adapter) {
         final PackageManager pm = getPackageManager();
+        ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
         int targetsToQuery = 0;
         for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) {
             final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
@@ -522,6 +523,11 @@
                 continue;
             }
             final ActivityInfo ai = dri.getResolveInfo().activityInfo;
+            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
+                    && sm.hasShareTargets(ai.packageName)) {
+                // Share targets will be queried from ShortcutManager
+                continue;
+            }
             final Bundle md = ai.metaData;
             final String serviceName = md != null ? convertServiceName(ai.packageName,
                     md.getString(ChooserTargetService.META_DATA_NAME)) : null;
diff --git a/core/java/com/android/internal/app/ColorDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index b03fde7..2ac0e4d 100644
--- a/core/java/com/android/internal/app/ColorDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.app;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
@@ -24,18 +23,13 @@
 import android.database.ContentObserver;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.ColorDisplayManager.AutoMode;
+import android.hardware.display.ColorDisplayManager.ColorMode;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.SystemProperties;
 import android.provider.Settings.Secure;
-import android.provider.Settings.System;
 import android.util.Slog;
 
-import com.android.internal.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.time.LocalTime;
 
 /**
@@ -49,35 +43,6 @@
     private static final String TAG = "ColorDisplayController";
     private static final boolean DEBUG = false;
 
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED, COLOR_MODE_AUTOMATIC})
-    public @interface ColorMode {}
-
-    /**
-     * Color mode with natural colors.
-     *
-     * @see #setColorMode(int)
-     */
-    public static final int COLOR_MODE_NATURAL = 0;
-    /**
-     * Color mode with boosted colors.
-     *
-     * @see #setColorMode(int)
-     */
-    public static final int COLOR_MODE_BOOSTED = 1;
-    /**
-     * Color mode with saturated colors.
-     *
-     * @see #setColorMode(int)
-     */
-    public static final int COLOR_MODE_SATURATED = 2;
-    /**
-     * Color mode with automatic colors.
-     *
-     * @see #setColorMode(int)
-     */
-    public static final int COLOR_MODE_AUTOMATIC = 3;
-
     private final Context mContext;
     private final int mUserId;
     private final ColorDisplayManager mColorDisplayManager;
@@ -197,74 +162,10 @@
     }
 
     /**
-     * Get the current color mode from system properties, or return -1.
-     *
-     * See com.android.server.display.DisplayTransformManager.
-     */
-    private @ColorMode int getCurrentColorModeFromSystemProperties() {
-        final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
-        if (displayColorSetting == 0) {
-            return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
-                    ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
-        } else if (displayColorSetting == 1) {
-            return COLOR_MODE_SATURATED;
-        } else if (displayColorSetting == 2) {
-            return COLOR_MODE_AUTOMATIC;
-        } else {
-            return -1;
-        }
-    }
-
-    private boolean isColorModeAvailable(@ColorMode int colorMode) {
-        final int[] availableColorModes = mContext.getResources().getIntArray(
-                R.array.config_availableColorModes);
-        if (availableColorModes != null) {
-            for (int mode : availableColorModes) {
-                if (mode == colorMode) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
      * Get the current color mode.
      */
     public int getColorMode() {
-        if (getAccessibilityTransformActivated()) {
-            if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
-                return COLOR_MODE_SATURATED;
-            } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
-                return COLOR_MODE_AUTOMATIC;
-            }
-        }
-
-        int colorMode = System.getIntForUser(mContext.getContentResolver(),
-                System.DISPLAY_COLOR_MODE, -1, mUserId);
-        if (colorMode == -1) {
-            // There might be a system property controlling color mode that we need to respect; if
-            // not, this will set a suitable default.
-            colorMode = getCurrentColorModeFromSystemProperties();
-        }
-
-        // This happens when a color mode is no longer available (e.g., after system update or B&R)
-        // or the device does not support any color mode.
-        if (!isColorModeAvailable(colorMode)) {
-            if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
-                colorMode = COLOR_MODE_NATURAL;
-            } else if (colorMode == COLOR_MODE_SATURATED
-                    && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
-                colorMode = COLOR_MODE_AUTOMATIC;
-            } else if (colorMode == COLOR_MODE_AUTOMATIC
-                    && isColorModeAvailable(COLOR_MODE_SATURATED)) {
-                colorMode = COLOR_MODE_SATURATED;
-            } else {
-                colorMode = -1;
-            }
-        }
-
-        return colorMode;
+        return mColorDisplayManager.getColorMode();
     }
 
     /**
@@ -273,11 +174,7 @@
      * @param colorMode the color mode
      */
     public void setColorMode(@ColorMode int colorMode) {
-        if (!isColorModeAvailable(colorMode)) {
-            throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
-        }
-        System.putIntForUser(mContext.getContentResolver(), System.DISPLAY_COLOR_MODE, colorMode,
-                mUserId);
+        mColorDisplayManager.setColorMode(colorMode);
     }
 
     /**
@@ -294,18 +191,6 @@
         return ColorDisplayManager.getMaximumColorTemperature(mContext);
     }
 
-    /**
-     * Returns true if any Accessibility color transforms are enabled.
-     */
-    public boolean getAccessibilityTransformActivated() {
-        final ContentResolver cr = mContext.getContentResolver();
-        return
-            Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
-                    0, mUserId) == 1
-            || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
-                    0, mUserId) == 1;
-    }
-
     private void onSettingChanged(@NonNull String setting) {
         if (DEBUG) {
             Slog.d(TAG, "onSettingChanged: " + setting);
@@ -328,13 +213,6 @@
                 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
                     mCallback.onColorTemperatureChanged(getColorTemperature());
                     break;
-                case System.DISPLAY_COLOR_MODE:
-                    mCallback.onDisplayColorModeChanged(getColorMode());
-                    break;
-                case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
-                case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
-                    mCallback.onAccessibilityTransformChanged(getAccessibilityTransformActivated());
-                    break;
             }
         }
     }
@@ -377,14 +255,6 @@
                         false /* notifyForDescendants */, mContentObserver, mUserId);
                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
                         false /* notifyForDescendants */, mContentObserver, mUserId);
-                cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
-                        false /* notifyForDecendants */, mContentObserver, mUserId);
-                cr.registerContentObserver(
-                        Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
-                        false /* notifyForDecendants */, mContentObserver, mUserId);
-                cr.registerContentObserver(
-                        Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
-                        false /* notifyForDecendants */, mContentObserver, mUserId);
             }
         }
     }
@@ -424,19 +294,5 @@
          * @param colorTemperature the color temperature to tint the screen
          */
         default void onColorTemperatureChanged(int colorTemperature) {}
-
-        /**
-         * Callback invoked when the color mode changes.
-         *
-         * @param displayColorMode the color mode
-         */
-        default void onDisplayColorModeChanged(int displayColorMode) {}
-
-        /**
-         * Callback invoked when Accessibility color transforms change.
-         *
-         * @param state the state Accessibility color transforms (true of active)
-         */
-        default void onAccessibilityTransformChanged(boolean state) {}
     }
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 7600dc9..8978496 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -100,6 +100,7 @@
      * @param backDisposition disposition flags
      * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
      * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
+     * @see android.inputmethodservice.InputMethodService#IME_INVISIBLE
      * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
      * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
      */
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 9bacf9b..f848346 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -64,6 +64,9 @@
 
     private boolean mUseBpfStats;
 
+    // A persistent Snapshot since device start for eBPF stats
+    private final NetworkStats mPersistSnapshot;
+
     // TODO: only do adjustments in NetworkStatsService and remove this.
     /**
      * (Stacked interface) -> (base interface) association for all connected ifaces since boot.
@@ -135,6 +138,7 @@
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
         mUseBpfStats = useBpfStats;
+        mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
     }
 
     public NetworkStats readBpfNetworkStatsDev() throws IOException {
@@ -268,6 +272,7 @@
         return stats;
     }
 
+    // TODO: delete the lastStats parameter
     private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces,
             int limitTag, NetworkStats lastStats) throws IOException {
         if (USE_NATIVE_PARSING) {
@@ -278,16 +283,28 @@
             } else {
                 stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             }
-            if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
-                    limitIfaces, limitTag, mUseBpfStats) != 0) {
-                throw new IOException("Failed to parse network stats");
+            if (mUseBpfStats) {
+                if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
+                        null, TAG_ALL, mUseBpfStats) != 0) {
+                    throw new IOException("Failed to parse network stats");
+                }
+                mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
+                mPersistSnapshot.combineAllValues(stats);
+                NetworkStats result = mPersistSnapshot.clone();
+                result.filter(limitUid, limitIfaces, limitTag);
+                return result;
+            } else {
+                if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
+                        limitIfaces, limitTag, mUseBpfStats) != 0) {
+                    throw new IOException("Failed to parse network stats");
+                }
+                if (SANITY_CHECK_NATIVE) {
+                    final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
+                            limitIfaces, limitTag);
+                    assertEquals(javaStats, stats);
+                }
+                return stats;
             }
-            if (SANITY_CHECK_NATIVE) {
-                final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
-                        limitIfaces, limitTag);
-                assertEquals(javaStats, stats);
-            }
-            return stats;
         } else {
             return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
         }
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 97d5a65..2ee902a 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -40,7 +40,7 @@
     void unbindInput();
 
     void startInput(in IBinder startInputToken, in IInputContext inputContext, int missingMethods,
-            in EditorInfo attribute, boolean restarting);
+            in EditorInfo attribute, boolean restarting, boolean preRenderImeViews);
 
     void createSession(in InputChannel channel, IInputSessionCallback callback);
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d79eb94..f06165c 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -451,6 +451,8 @@
         optional SettingProto gup_blacklist = 11;
         // List of Apps that are allowed to use Game Driver package.
         optional SettingProto game_driver_whitelist = 12;
+        // ANGLE - List of Apps that can check ANGLE rules
+        optional SettingProto angle_whitelist = 13;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0c0b4d7..4a54bd7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3528,12 +3528,6 @@
         android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
 
-    <!-- Allows an application to access and modify always-on VPN configuration.
-         <p>Not for use by third-party or privileged applications.
-         @hide -->
-    <permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN"
-        android:protectionLevel="signature" />
-
     <!-- Allows an application to capture audio output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d93cd82..49f2c84 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3729,9 +3729,6 @@
     <!-- Whether or not the "SMS app service" feature is enabled -->
     <bool name="config_useSmsAppService">true</bool>
 
-    <!-- Component name for default assistant on this device -->
-    <string name="config_defaultAssistantComponentName">#+UNSET</string>
-
     <!-- Class name for the InputEvent compatibility processor override.
          Empty string means use the default compatibility processor
          (android.view.InputEventCompatProcessor). -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4235341..ec1bac1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2988,7 +2988,7 @@
     </public-group>
 
     <public-group type="array" first-id="0x01070006">
-      <!-- @hide @SystemApi -->
+      <!-- @hide @TestApi @SystemApi -->
       <public name="config_defaultRoleHolders" />
     </public-group>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cbb4cb2..d556130 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3528,8 +3528,6 @@
 
   <java-symbol type="bool" name="config_useSmsAppService" />
 
-  <java-symbol type="string" name="config_defaultAssistantComponentName" />
-
   <java-symbol type="id" name="transition_overlay_view_tag" />
 
   <java-symbol type="dimen" name="rounded_corner_radius" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 318f2ea..a15dbc8 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -390,9 +390,8 @@
                     Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
                     Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED,
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
+                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
@@ -482,6 +481,7 @@
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
                     Settings.Global.GUP_DEV_ALL_APPS,
                     Settings.Global.GUP_DEV_OPT_IN_APPS,
                     Settings.Global.GUP_DEV_OPT_OUT_APPS,
@@ -574,7 +574,6 @@
                  Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
                  Settings.Secure.ALWAYS_ON_VPN_APP,
                  Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
-                 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
                  Settings.Secure.ANDROID_ID,
                  Settings.Secure.ANR_SHOW_BACKGROUND,
                  Settings.Secure.ASSISTANT,
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index d57fa8f..6a83c29b 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -20,6 +20,7 @@
 import static android.view.WindowInsets.Type.sideBars;
 import static android.view.WindowInsets.Type.topBar;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Insets;
@@ -73,4 +74,29 @@
         assertEquals(Insets.of(0, 50, 0, 0), insets.getInsets(topBar()));
         assertEquals(Insets.of(0, 0, 30, 10), insets.getInsets(sideBars()));
     }
+
+    // TODO: Move this to CTS once API made public
+    @Test
+    public void visibility() {
+        Builder b = new WindowInsets.Builder();
+        b.setInsets(sideBars(), Insets.of(0, 0, 0, 100));
+        b.setInsets(ime(), Insets.of(0, 0, 0, 300));
+        b.setVisible(sideBars(), true);
+        b.setVisible(ime(), true);
+        WindowInsets insets = b.build();
+        assertTrue(insets.isVisible(sideBars()));
+        assertTrue(insets.isVisible(sideBars() | ime()));
+        assertFalse(insets.isVisible(sideBars() | topBar()));
+    }
+
+    // TODO: Move this to CTS once API made public
+    @Test
+    public void consume_doesntChangeVisibility() {
+        Builder b = new WindowInsets.Builder();
+        b.setInsets(ime(), Insets.of(0, 0, 0, 300));
+        b.setVisible(ime(), true);
+        WindowInsets insets = b.build();
+        insets = insets.consumeSystemWindowInsets();
+        assertTrue(insets.isVisible(ime()));
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index b1b7416..73af567 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -18,9 +18,10 @@
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.CONVERSATION_ACTIONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_TYPE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -71,7 +72,8 @@
                 new TextClassifierEvent.Builder(
                         TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS,
                         TextClassifierEvent.TYPE_SMART_ACTION)
-                        .setEntityType(ConversationAction.TYPE_CALL_PHONE)
+                        .setEntityTypes(ConversationAction.TYPE_CALL_PHONE)
+                        .setScore(0.5f)
                         .setEventTime(EVENT_TIME)
                         .setEventContext(textClassificationContext)
                         .build();
@@ -83,15 +85,18 @@
         LogMaker logMaker = captor.getValue();
         assertThat(logMaker.getCategory()).isEqualTo(
                 CONVERSATION_ACTIONS);
-        assertThat(logMaker.getType()).isEqualTo(
+        assertThat(logMaker.getSubtype()).isEqualTo(
                 ACTION_TEXT_SELECTION_SMART_SHARE);
-        assertThat(logMaker.getTaggedData(FIELD_SELECTION_ENTITY_TYPE))
+        assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE))
                 .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
+        assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE))
+                .isWithin(0.00001f).of(0.5f);
         assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
                 .isEqualTo(EVENT_TIME);
         assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
-        assertThat(logMaker.getTaggedData(FIELD_SELECTION_WIDGET_TYPE))
+        assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE))
                 .isEqualTo(WIDGET_TYPE);
+
     }
 
     @Test
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 1661905..8508274 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -31,8 +31,8 @@
 
 // Cache size limits.
 static const size_t maxKeySize = 1024;
-static const size_t maxValueSize = 64 * 1024;
-static const size_t maxTotalSize = 512 * 1024;
+static const size_t maxValueSize = 512 * 1024;
+static const size_t maxTotalSize = 1024 * 1024;
 
 ShaderCache::ShaderCache() {
     // There is an "incomplete FileBlobCache type" compilation error, if ctor is moved to header.
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9b6ad38..9064ebe 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -81,5 +81,5 @@
         "com.android.keyguard",
     ],
 
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 052566d..e591ea9 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -65,8 +65,9 @@
         <com.android.systemui.statusbar.car.CarFacetButton
             android:id="@+id/music_nav"
             style="@style/NavigationBarButton"
+            systemui:categories="android.intent.category.APP_MUSIC"
             systemui:icon="@drawable/car_ic_music"
-            systemui:intent="intent:#Intent;component=com.android.car.media/.MediaActivity;launchFlags=0x14000000;end"
+            systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
             systemui:packages="com.android.car.media"
             systemui:selectedIcon="@drawable/car_ic_music_selected"
             systemui:useMoreIcon="false"
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index dbddf71..b37c5e6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -114,9 +114,16 @@
                     new DeviceProvisionedController.DeviceProvisionedListener() {
                         @Override
                         public void onDeviceProvisionedChanged() {
-                            mDeviceIsProvisioned =
-                                    mDeviceProvisionedController.isDeviceProvisioned();
-                            restartNavBars();
+                            mHandler.post(() -> {
+                                // on initial boot we are getting a call even though the value
+                                // is the same so we are confirming the reset is needed
+                                boolean deviceProvisioned =
+                                        mDeviceProvisionedController.isDeviceProvisioned();
+                                if (mDeviceIsProvisioned != deviceProvisioned) {
+                                    mDeviceIsProvisioned = deviceProvisioned;
+                                    restartNavBars();
+                                }
+                            });
                         }
                     });
         }
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 0d528e7..bc6e2fc 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -202,7 +202,7 @@
         }
         TextClassifierEvent textClassifierEvent =
                 createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
-                        .setEntityType(ConversationAction.TYPE_TEXT_REPLY)
+                        .setEntityTypes(ConversationAction.TYPE_TEXT_REPLY)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
@@ -225,7 +225,7 @@
         }
         TextClassifierEvent textClassifierEvent =
                 createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
-                        .setEntityType(actionType)
+                        .setEntityTypes(actionType)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 7357fe6..42afb69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.applications;
 
+import android.app.Application;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentFilter;
@@ -123,4 +124,12 @@
         return null;
     }
 
+    /**
+     * Returns a boolean indicating whether the given package is a hidden system module
+     */
+    public static boolean isHiddenSystemModule(Context context, String packageName) {
+        return ApplicationsState.getInstance((Application) context.getApplicationContext())
+            .isHiddenModule(packageName);
+    }
+
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index a936df2..c9fbc7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -29,6 +29,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageStats;
@@ -71,6 +72,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
@@ -95,9 +97,14 @@
     static ApplicationsState sInstance;
 
     public static ApplicationsState getInstance(Application app) {
+        return getInstance(app, AppGlobals.getPackageManager());
+    }
+
+    @VisibleForTesting
+    static ApplicationsState getInstance(Application app, IPackageManager iPackageManager) {
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new ApplicationsState(app);
+                sInstance = new ApplicationsState(app, iPackageManager);
             }
             return sInstance;
         }
@@ -132,6 +139,7 @@
     String mCurComputingSizePkg;
     int mCurComputingSizeUserId;
     boolean mSessionsChanged;
+    final HashSet<String> mHiddenModules = new HashSet<>();
 
     // Temporary for dispatching session callbacks.  Only touched by main thread.
     final ArrayList<WeakReference<Session>> mActiveSessions = new ArrayList<>();
@@ -172,11 +180,11 @@
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
             FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
 
-    private ApplicationsState(Application app) {
+    private ApplicationsState(Application app, IPackageManager iPackageManager) {
         mContext = app;
         mPm = mContext.getPackageManager();
         mDrawableFactory = IconDrawableFactory.newInstance(mContext);
-        mIpm = AppGlobals.getPackageManager();
+        mIpm = iPackageManager;
         mUm = mContext.getSystemService(UserManager.class);
         mStats = mContext.getSystemService(StorageStatsManager.class);
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
@@ -194,6 +202,13 @@
         mRetrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS |
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 
+        final List<ModuleInfo> moduleInfos = mPm.getInstalledModules(0 /* flags */);
+        for (ModuleInfo info : moduleInfos) {
+            if (info.isHidden()) {
+                mHiddenModules.add(info.getPackageName());
+            }
+        }
+
         /**
          * This is a trick to prevent the foreground thread from being delayed.
          * The problem is that Dalvik monitors are initially spin locks, to keep
@@ -283,6 +298,10 @@
                 }
                 mHaveDisabledApps = true;
             }
+            if (isHiddenModule(info.packageName)) {
+                mApplications.remove(i--);
+                continue;
+            }
             if (!mHaveInstantApps && AppUtils.isInstant(info)) {
                 mHaveInstantApps = true;
             }
@@ -314,10 +333,15 @@
     public boolean haveDisabledApps() {
         return mHaveDisabledApps;
     }
+
     public boolean haveInstantApps() {
         return mHaveInstantApps;
     }
 
+    boolean isHiddenModule(String packageName) {
+        return mHiddenModules.contains(packageName);
+    }
+
     void doPauseIfNeededLocked() {
         if (!mResumed) {
             return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
index d957801..305a1ff 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -22,7 +22,6 @@
 import android.app.usage.NetworkStats;
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.INetworkStatsSession;
 import android.net.NetworkPolicy;
@@ -35,14 +34,14 @@
 import android.text.format.DateUtils;
 import android.util.Pair;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.loader.content.AsyncTaskLoader;
+
 import com.android.settingslib.NetworkPolicyEditor;
 
 import java.time.ZonedDateTime;
 import java.util.Iterator;
 
-import androidx.annotation.VisibleForTesting;
-import androidx.loader.content.AsyncTaskLoader;
-
 /**
  * Loader for network data usage history. It returns a list of usage data per billing cycle.
  */
@@ -121,8 +120,7 @@
 
             long cycleEnd = historyEnd;
             while (cycleEnd > historyStart) {
-                final long cycleStart = Math.max(
-                    historyStart, cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4));
+                final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4);
                 recordUsage(cycleStart, cycleEnd);
                 cycleEnd = cycleStart;
             }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index ccec175a..a098ecc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -18,7 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadow.api.Shadow.extract;
@@ -33,12 +35,16 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.IconDrawableFactory;
 
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -46,11 +52,11 @@
 import com.android.settingslib.applications.ApplicationsState.Session;
 import com.android.settingslib.testutils.shadow.ShadowUserManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -78,6 +84,8 @@
 
     /** Class under test */
     private ApplicationsState mApplicationsState;
+    private Session mSession;
+
 
     @Mock
     private Callbacks mCallbacks;
@@ -85,6 +93,8 @@
     private ArgumentCaptor<ArrayList<AppEntry>> mAppEntriesCaptor;
     @Mock
     private StorageStatsManager mStorageStatsManager;
+    @Mock
+    private IPackageManager mPackageManagerService;
 
     @Implements(value = IconDrawableFactory.class)
     public static class ShadowIconDrawableFactory {
@@ -99,6 +109,11 @@
     public static class ShadowPackageManager extends
             org.robolectric.shadows.ShadowApplicationPackageManager {
 
+        // test installed modules, 2 regular, 2 hidden
+        private final String[] mModuleNames = {
+            "test.module.1", "test.hidden.module.2", "test.hidden.module.3", "test.module.4"};
+        private final List<ModuleInfo> mInstalledModules = new ArrayList<>();
+
         @Implementation
         protected ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
             ResolveInfo resolveInfo = new ResolveInfo();
@@ -109,6 +124,16 @@
             return ComponentName.createRelative(resolveInfo.activityInfo.packageName, "foo");
         }
 
+        @Implementation
+        public List<ModuleInfo> getInstalledModules(int flags) {
+            if (mInstalledModules.isEmpty()) {
+                for (String moduleName : mModuleNames) {
+                    mInstalledModules.add(createModuleInfo(moduleName));
+                }
+            }
+            return mInstalledModules;
+        }
+
         public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                 @PackageManager.ResolveInfoFlags int flags, @UserIdInt int userId) {
             List<ResolveInfo> resolveInfos = new ArrayList<>();
@@ -121,6 +146,15 @@
             resolveInfos.add(resolveInfo);
             return resolveInfos;
         }
+
+        private ModuleInfo createModuleInfo(String packageName) {
+            final ModuleInfo info = new ModuleInfo();
+            info.setName(packageName);
+            info.setPackageName(packageName);
+            // will treat any app with package name that contains "hidden" as hidden module
+            info.setHidden(!TextUtils.isEmpty(packageName) && packageName.contains("hidden"));
+            return info;
+        }
     }
 
     @Before
@@ -136,12 +170,28 @@
         storageStats.codeBytes = 10;
         storageStats.dataBytes = 20;
         storageStats.cacheBytes = 30;
-        when(mStorageStatsManager.queryStatsForPackage(ArgumentMatchers.any(UUID.class),
-                anyString(), ArgumentMatchers.any(UserHandle.class))).thenReturn(storageStats);
+        when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
+                anyString(), any(UserHandle.class))).thenReturn(storageStats);
+
+        // Set up 3 installed apps, in which 1 is hidden module
+        final List<ApplicationInfo> infos = new ArrayList<>();
+        infos.add(createApplicationInfo("test.package.1"));
+        infos.add(createApplicationInfo("test.hidden.module.2"));
+        infos.add(createApplicationInfo("test.package.3"));
+        when(mPackageManagerService.getInstalledApplications(
+            anyInt() /* flags */, anyInt() /* userId */)).thenReturn(new ParceledListSlice(infos));
 
         ApplicationsState.sInstance = null;
-        mApplicationsState = ApplicationsState.getInstance(RuntimeEnvironment.application);
+        mApplicationsState =
+            ApplicationsState.getInstance(RuntimeEnvironment.application, mPackageManagerService);
         mApplicationsState.clearEntries();
+
+        mSession = mApplicationsState.newSession(mCallbacks);
+    }
+
+    @After
+    public void tearDown() {
+        mSession.onDestroy();
     }
 
     private ApplicationInfo createApplicationInfo(String packageName) {
@@ -187,12 +237,11 @@
 
     @Test
     public void testDefaultSessionLoadsAll() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.onResume();
+        mSession.onResume();
 
         addApp(HOME_PACKAGE_NAME, 1);
         addApp(LAUNCHABLE_PACKAGE_NAME, 2);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -211,17 +260,15 @@
         AppEntry launchableEntry = findAppEntry(appEntries, 2);
         assertThat(launchableEntry.hasLauncherEntry).isTrue();
         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsIconsOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -232,17 +279,15 @@
         assertThat(launchableEntry.icon).isNotNull();
         assertThat(launchableEntry.size).isEqualTo(-1);
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsSizesOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -253,17 +298,15 @@
         assertThat(launchableEntry.icon).isNull();
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
         assertThat(launchableEntry.size).isGreaterThan(0L);
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsHomeOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
+        mSession.onResume();
 
         addApp(HOME_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -275,17 +318,15 @@
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
         assertThat(launchableEntry.size).isEqualTo(-1);
         assertThat(launchableEntry.isHomeApp).isTrue();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsLeanbackOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -298,6 +339,16 @@
         assertThat(launchableEntry.isHomeApp).isFalse();
         assertThat(launchableEntry.hasLauncherEntry).isTrue();
         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
-        session.onDestroy();
     }
+
+    @Test
+    public void onResume_shouldNotIncludeSystemHiddenModule() {
+        mSession.onResume();
+
+        final List<ApplicationInfo> mApplications = mApplicationsState.mApplications;
+        assertThat(mApplications).hasSize(2);
+        assertThat(mApplications.get(0).packageName).isEqualTo("test.package.1");
+        assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
+    }
+
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
index 2d8ea12..b8a143a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -130,7 +130,8 @@
             .thenReturn(networkHistory);
         final long now = System.currentTimeMillis();
         final long fourWeeksAgo = now - (DateUtils.WEEK_IN_MILLIS * 4);
-        when(networkHistory.getStart()).thenReturn(fourWeeksAgo);
+        final long twoDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 2);
+        when(networkHistory.getStart()).thenReturn(twoDaysAgo);
         when(networkHistory.getEnd()).thenReturn(now);
 
         mLoader.loadFourWeeksData();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 850a3c2..aff6f04 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -698,6 +698,9 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
                 GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
         dumpSetting(s, p,
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
+                GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
+        dumpSetting(s, p,
                 Settings.Global.GPU_DEBUG_LAYER_APP,
                 GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 8be67d9..0a62b7c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -73,7 +73,7 @@
         "com.android.keyguard",
     ],
 
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
 
 android_library {
@@ -127,7 +127,7 @@
         "--extra-packages",
         "com.android.keyguard:com.android.systemui",
     ],
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
 
 android_app {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 0b1dab1..fc84332 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -20,14 +20,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import java.util.ArrayList;
-
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
+
+import java.util.ArrayList;
 
 @ProvidesInterface(action = NotificationMenuRowPlugin.ACTION,
         version = NotificationMenuRowPlugin.VERSION)
@@ -149,6 +149,12 @@
     public boolean canBeDismissed();
 
     /**
+     * Informs the menu whether dismiss gestures are left-to-right or right-to-left.
+     */
+    default void setDismissRtl(boolean dismissRtl) {
+    }
+
+    /**
      * Determines whether the menu should remain open given its current state, or snap closed.
      * @return true if the menu should remain open, false otherwise.
      */
diff --git a/packages/SystemUI/res/layout/qs_footer_carrier.xml b/packages/SystemUI/res/layout/qs_footer_carrier.xml
new file mode 100644
index 0000000..bd492b0
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_footer_carrier.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ 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
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear_footer_carrier"
+    android:layout_width="0dp"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:layout_weight="1"
+    android:gravity="center_vertical|start"
+    android:background="@android:color/transparent"
+    android:clickable="false"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:paddingStart="16dp" >
+
+    <include
+        layout="@layout/mobile_signal_group"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:visibility="gone" />
+
+    <view class="com.android.systemui.qs.QSFooterImpl$QSCarrierText"
+        android:id="@+id/qs_carrier_text"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:ellipsize="marquee"
+        android:textAppearance="@style/TextAppearance.QS.CarrierInfo"
+        android:textColor="?android:attr/textColorPrimary"
+        android:textDirection="locale"
+        android:singleLine="true" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 890bf5d..abf9e05 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -42,30 +42,31 @@
         android:gravity="end" >
 
         <LinearLayout
+            android:id="@+id/qs_mobile"
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1"
             android:gravity="center_vertical|start"
-            android:paddingStart="16dp">
+            android:orientation="horizontal"
+            android:layout_marginEnd="32dp">
 
             <include
-                layout="@layout/mobile_signal_group"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="8dp"
+                layout="@layout/qs_footer_carrier"
+                android:id="@+id/carrier1" />
+
+            <View
+                android:id="@+id/qs_carrier_divider"
+                android:layout_width="2dp"
+                android:layout_height="match_parent"
+                android:layout_marginTop="15dp"
+                android:layout_marginBottom="15dp"
+                android:background="?android:attr/dividerVertical"
                 android:visibility="gone" />
 
-            <com.android.keyguard.CarrierText
-                android:id="@+id/qs_carrier_text"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_marginEnd="32dp"
-                android:ellipsize="marquee"
-                android:textAppearance="@style/TextAppearance.QS.CarrierInfo"
-                android:textColor="?android:attr/textColorPrimary"
-                android:textDirection="locale"
-                android:singleLine="true" />
+            <include
+                layout="@layout/qs_footer_carrier"
+                android:id="@+id/carrier2"
+                android:visibility="gone"/>
 
         </LinearLayout>
 
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index bd34bea..5e32dd5 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -68,6 +68,7 @@
     <item type="id" name="panel_alpha_animator_tag"/>
     <item type="id" name="panel_alpha_animator_start_tag"/>
     <item type="id" name="panel_alpha_animator_end_tag"/>
+    <item type="id" name="cross_fade_layer_type_changed_tag"/>
 
     <!-- Whether the icon is from a notification for which targetSdk < L -->
     <item type="id" name="icon_is_pre_L"/>
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index b7d5197..adcb7a1 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -17,29 +17,14 @@
 package com.android.keyguard;
 
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.TypedArray;
-import android.net.ConnectivityManager;
-import android.net.wifi.WifiManager;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.text.method.SingleLineTransformationMethod;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.settingslib.WirelessUtils;
-
-import java.util.List;
 import java.util.Locale;
-import java.util.Objects;
 
 public class CarrierText extends TextView {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -47,77 +32,30 @@
 
     private static CharSequence mSeparator;
 
-    private final boolean mIsEmergencyCallCapable;
-
-    private boolean mTelephonyCapable;
-
     private boolean mShowMissingSim;
 
     private boolean mShowAirplaneMode;
+    private boolean mShouldMarquee;
 
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private CarrierTextController mCarrierTextController;
 
-    private WifiManager mWifiManager;
+    private CarrierTextController.CarrierTextCallback mCarrierTextCallback =
+            new CarrierTextController.CarrierTextCallback() {
+                @Override
+                public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+                    setText(info.carrierText);
+                }
 
-    private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
+                @Override
+                public void startedGoingToSleep() {
+                    setSelected(false);
+                }
 
-    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onRefreshCarrierInfo() {
-            if (DEBUG) Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: "
-                    + Boolean.toString(mTelephonyCapable));
-            updateCarrierText();
-        }
-
-        public void onFinishedGoingToSleep(int why) {
-            setSelected(false);
-        };
-
-        public void onStartedWakingUp() {
-            setSelected(true);
-        };
-
-        @Override
-        public void onTelephonyCapable(boolean capable) {
-            if (DEBUG) Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: "
-                    + Boolean.toString(capable));
-            mTelephonyCapable = capable;
-            updateCarrierText();
-        }
-
-        public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
-            if (slotId < 0) {
-                Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId
-                        + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
-                return;
-            }
-
-            if (DEBUG) Log.d(TAG,"onSimStateChanged: " + getStatusForIccState(simState));
-            if (getStatusForIccState(simState) == StatusMode.SimIoError) {
-                mSimErrorState[slotId] = true;
-                updateCarrierText();
-            } else if (mSimErrorState[slotId]) {
-                mSimErrorState[slotId] = false;
-                updateCarrierText();
-            }
-        }
-    };
-
-    /**
-     * The status of this lock screen. Primarily used for widgets on LockScreen.
-     */
-    private static enum StatusMode {
-        Normal, // Normal case (sim card present, it's not locked)
-        NetworkLocked, // SIM card is 'network locked'.
-        SimMissing, // SIM card is missing.
-        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
-        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
-        SimLocked, // SIM card is currently locked
-        SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
-        SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
-        SimIoError, // SIM card is faulty
-        SimUnknown // SIM card is unknown
-    }
+                @Override
+                public void finishedWakingUp() {
+                    setSelected(true);
+                }
+            };
 
     public CarrierText(Context context) {
         this(context, null);
@@ -125,8 +63,6 @@
 
     public CarrierText(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mIsEmergencyCallCapable = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
         boolean useAllCaps;
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 attrs, R.styleable.CarrierText, 0, 0);
@@ -138,132 +74,6 @@
             a.recycle();
         }
         setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
-
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-    }
-
-    /**
-     * Checks if there are faulty cards. Adds the text depending on the slot of the card
-     * @param text: current carrier text based on the sim state
-     * @param noSims: whether a valid sim card is inserted
-     * @return text
-    */
-    private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) {
-        final CharSequence carrier = "";
-        CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
-            IccCardConstants.State.CARD_IO_ERROR, carrier);
-        for (int index = 0; index < mSimErrorState.length; index++) {
-            if (mSimErrorState[index]) {
-                // In the case when no sim cards are detected but a faulty card is inserted
-                // overwrite the text and only show "Invalid card"
-                if (noSims) {
-                    return concatenate(carrierTextForSimIOError,
-                        getContext().getText(com.android.internal.R.string.emergency_calls_only));
-                } else if (index == 0) {
-                    // prepend "Invalid card" when faulty card is inserted in slot 0
-                    text = concatenate(carrierTextForSimIOError, text);
-                } else {
-                    // concatenate "Invalid card" when faulty card is inserted in slot 1
-                    text = concatenate(text, carrierTextForSimIOError);
-                }
-            }
-        }
-        return text;
-    }
-
-    protected void updateCarrierText() {
-        boolean allSimsMissing = true;
-        boolean anySimReadyAndInService = false;
-        CharSequence displayText = null;
-
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
-        final int N = subs.size();
-        if (DEBUG) Log.d(TAG, "updateCarrierText(): " + N);
-        for (int i = 0; i < N; i++) {
-            int subId = subs.get(i).getSubscriptionId();
-            State simState = mKeyguardUpdateMonitor.getSimState(subId);
-            CharSequence carrierName = subs.get(i).getCarrierName();
-            CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
-            if (DEBUG) {
-                Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
-            }
-            if (carrierTextForSimState != null) {
-                allSimsMissing = false;
-                displayText = concatenate(displayText, carrierTextForSimState);
-            }
-            if (simState == IccCardConstants.State.READY) {
-                ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
-                if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
-                    // hack for WFC (IWLAN) not turning off immediately once
-                    // Wi-Fi is disassociated or disabled
-                    if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                            || (mWifiManager.isWifiEnabled()
-                                    && mWifiManager.getConnectionInfo() != null
-                                    && mWifiManager.getConnectionInfo().getBSSID() != null)) {
-                        if (DEBUG) {
-                            Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss);
-                        }
-                        anySimReadyAndInService = true;
-                    }
-                }
-            }
-        }
-        if (allSimsMissing) {
-            if (N != 0) {
-                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
-                // This depends on mPlmn containing the text "Emergency calls only" when the radio
-                // has some connectivity. Otherwise, it should be null or empty and just show
-                // "No SIM card"
-                // Grab the first subscripton, because they all should contain the emergency text,
-                // described above.
-                displayText =  makeCarrierStringOnEmergencyCapable(
-                        getMissingSimMessage(), subs.get(0).getCarrierName());
-            } else {
-                // We don't have a SubscriptionInfo to get the emergency calls only from.
-                // Grab it from the old sticky broadcast if possible instead. We can use it
-                // here because no subscriptions are active, so we don't have
-                // to worry about MSIM clashing.
-                CharSequence text =
-                        getContext().getText(com.android.internal.R.string.emergency_calls_only);
-                Intent i = getContext().registerReceiver(null,
-                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
-                if (i != null) {
-                    String spn = "";
-                    String plmn = "";
-                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
-                        spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
-                    }
-                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
-                        plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
-                    }
-                    if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
-                    if (Objects.equals(plmn, spn)) {
-                        text = plmn;
-                    } else {
-                        text = concatenate(plmn, spn);
-                    }
-                }
-                displayText =  makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
-            }
-        }
-
-        displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing);
-        // APM (airplane mode) != no carrier state. There are carrier services
-        // (e.g. WFC = Wi-Fi calling) which may operate in APM.
-        if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
-            displayText = getAirplaneModeMessage();
-        }
-        setText(displayText);
-    }
-
-    private String getMissingSimMessage() {
-        return mShowMissingSim && mTelephonyCapable
-                ? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
-    }
-
-    private String getAirplaneModeMessage() {
-        return mShowAirplaneMode
-                ? getContext().getString(R.string.airplane_mode) : "";
     }
 
     @Override
@@ -271,36 +81,27 @@
         super.onFinishInflate();
         mSeparator = getResources().getString(
                 com.android.internal.R.string.kg_text_message_separator);
-        boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
-        setSelected(shouldMarquee); // Allow marquee to work.
+        mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode,
+                mShowMissingSim);
+        mShouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
+        setSelected(mShouldMarquee); // Allow marquee to work.
     }
 
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        if (ConnectivityManager.from(mContext).isNetworkSupported(
-                ConnectivityManager.TYPE_MOBILE)) {
-            mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-            mKeyguardUpdateMonitor.registerCallback(mCallback);
-        } else {
-            // Don't listen and clear out the text when the device isn't a phone.
-            mKeyguardUpdateMonitor = null;
-            setText("");
-        }
+        mCarrierTextController.setListening(mCarrierTextCallback);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mKeyguardUpdateMonitor != null) {
-            mKeyguardUpdateMonitor.removeCallback(mCallback);
-        }
+        mCarrierTextController.setListening(null);
     }
 
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
-
         // Only show marquee when visible
         if (visibility == VISIBLE) {
             setEllipsize(TextUtils.TruncateAt.MARQUEE);
@@ -309,167 +110,6 @@
         }
     }
 
-    /**
-     * Top-level function for creating carrier text. Makes text based on simState, PLMN
-     * and SPN as well as device capabilities, such as being emergency call capable.
-     *
-     * @param simState
-     * @param text
-     * @param spn
-     * @return Carrier text if not in missing state, null otherwise.
-     */
-    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
-            CharSequence text) {
-        CharSequence carrierText = null;
-        StatusMode status = getStatusForIccState(simState);
-        switch (status) {
-            case Normal:
-                carrierText = text;
-                break;
-
-            case SimNotReady:
-                // Null is reserved for denoting missing, in this case we have nothing to display.
-                carrierText = ""; // nothing to display yet.
-                break;
-
-            case NetworkLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        mContext.getText(R.string.keyguard_network_locked_message), text);
-                break;
-
-            case SimMissing:
-                carrierText = null;
-                break;
-
-            case SimPermDisabled:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(
-                                R.string.keyguard_permanent_disabled_sim_message_short),
-                        text);
-                break;
-
-            case SimMissingLocked:
-                carrierText = null;
-                break;
-
-            case SimLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_sim_locked_message),
-                        text);
-                break;
-
-            case SimPukLocked:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_sim_puk_locked_message),
-                        text);
-                break;
-            case SimIoError:
-                carrierText = makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_sim_error_message_short),
-                        text);
-                break;
-            case SimUnknown:
-                carrierText = null;
-                break;
-        }
-
-        return carrierText;
-    }
-
-    /*
-     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
-     */
-    private CharSequence makeCarrierStringOnEmergencyCapable(
-            CharSequence simMessage, CharSequence emergencyCallMessage) {
-        if (mIsEmergencyCallCapable) {
-            return concatenate(simMessage, emergencyCallMessage);
-        }
-        return simMessage;
-    }
-
-    /**
-     * Determine the current status of the lock screen given the SIM state and other stuff.
-     */
-    private StatusMode getStatusForIccState(IccCardConstants.State simState) {
-        // Since reading the SIM may take a while, we assume it is present until told otherwise.
-        if (simState == null) {
-            return StatusMode.Normal;
-        }
-
-        final boolean missingAndNotProvisioned =
-                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
-                && (simState == IccCardConstants.State.ABSENT ||
-                        simState == IccCardConstants.State.PERM_DISABLED);
-
-        // Assume we're NETWORK_LOCKED if not provisioned
-        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
-        switch (simState) {
-            case ABSENT:
-                return StatusMode.SimMissing;
-            case NETWORK_LOCKED:
-                return StatusMode.SimMissingLocked;
-            case NOT_READY:
-                return StatusMode.SimNotReady;
-            case PIN_REQUIRED:
-                return StatusMode.SimLocked;
-            case PUK_REQUIRED:
-                return StatusMode.SimPukLocked;
-            case READY:
-                return StatusMode.Normal;
-            case PERM_DISABLED:
-                return StatusMode.SimPermDisabled;
-            case UNKNOWN:
-                return StatusMode.SimUnknown;
-            case CARD_IO_ERROR:
-                return StatusMode.SimIoError;
-        }
-        return StatusMode.SimUnknown;
-    }
-
-    private static CharSequence concatenate(CharSequence plmn, CharSequence spn) {
-        final boolean plmnValid = !TextUtils.isEmpty(plmn);
-        final boolean spnValid = !TextUtils.isEmpty(spn);
-        if (plmnValid && spnValid) {
-            return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
-        } else if (plmnValid) {
-            return plmn;
-        } else if (spnValid) {
-            return spn;
-        } else {
-            return "";
-        }
-    }
-
-    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
-            String plmn, String spn) {
-        int carrierHelpTextId = 0;
-        StatusMode status = getStatusForIccState(simState);
-        switch (status) {
-            case NetworkLocked:
-                carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
-                break;
-
-            case SimMissing:
-                carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
-                break;
-
-            case SimPermDisabled:
-                carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
-                break;
-
-            case SimMissingLocked:
-                carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
-                break;
-
-            case Normal:
-            case SimLocked:
-            case SimPukLocked:
-                break;
-        }
-
-        return mContext.getText(carrierHelpTextId);
-    }
-
     private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
         private final Locale mLocale;
         private final boolean mAllCaps;
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
new file mode 100644
index 0000000..2ce6965
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.settingslib.WirelessUtils;
+import com.android.systemui.Dependency;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Controller that generates text including the carrier names and/or the status of all the SIM
+ * interfaces in the device. Through a callback, the updates can be retrieved either as a list or
+ * separated by a given separator {@link CharSequence}.
+ */
+public class CarrierTextController {
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
+    private static final String TAG = "CarrierTextController";
+
+    private final boolean mIsEmergencyCallCapable;
+    private boolean mTelephonyCapable;
+    private boolean mShowMissingSim;
+    private boolean mShowAirplaneMode;
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private WifiManager mWifiManager;
+    private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
+    private CarrierTextCallback mCarrierTextCallback;
+    private Context mContext;
+    private CharSequence mSeparator;
+    private WakefulnessLifecycle mWakefulnessLifecycle;
+    private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+            new WakefulnessLifecycle.Observer() {
+                @Override
+                public void onFinishedWakingUp() {
+                    mCarrierTextCallback.finishedWakingUp();
+                }
+
+                @Override
+                public void onStartedGoingToSleep() {
+                    mCarrierTextCallback.startedGoingToSleep();
+                }
+            };
+
+    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onRefreshCarrierInfo() {
+            if (DEBUG) {
+                Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: "
+                        + Boolean.toString(mTelephonyCapable));
+            }
+            updateCarrierText();
+        }
+
+        @Override
+        public void onTelephonyCapable(boolean capable) {
+            if (DEBUG) {
+                Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: "
+                        + Boolean.toString(capable));
+            }
+            mTelephonyCapable = capable;
+            updateCarrierText();
+        }
+
+        public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+            if (slotId < 0) {
+                Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId
+                        + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
+                return;
+            }
+
+            if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState));
+            if (getStatusForIccState(simState) == CarrierTextController.StatusMode.SimIoError) {
+                mSimErrorState[slotId] = true;
+                updateCarrierText();
+            } else if (mSimErrorState[slotId]) {
+                mSimErrorState[slotId] = false;
+                updateCarrierText();
+            }
+        }
+    };
+
+    /**
+     * The status of this lock screen. Primarily used for widgets on LockScreen.
+     */
+    private enum StatusMode {
+        Normal, // Normal case (sim card present, it's not locked)
+        NetworkLocked, // SIM card is 'network locked'.
+        SimMissing, // SIM card is missing.
+        SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access
+        SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times
+        SimLocked, // SIM card is currently locked
+        SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
+        SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
+        SimIoError, // SIM card is faulty
+        SimUnknown // SIM card is unknown
+    }
+
+    /**
+     * Controller that provides updates on text with carriers names or SIM status.
+     * Used by {@link CarrierText}.
+     *
+     * @param separator Separator between different parts of the text
+     */
+    public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode,
+            boolean showMissingSim) {
+        mContext = context;
+        mIsEmergencyCallCapable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
+
+        mShowAirplaneMode = showAirplaneMode;
+        mShowMissingSim = showMissingSim;
+
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mSeparator = separator;
+        mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
+    }
+
+    /**
+     * Checks if there are faulty cards. Adds the text depending on the slot of the card
+     *
+     * @param text:   current carrier text based on the sim state
+     * @param noSims: whether a valid sim card is inserted
+     * @return text
+     */
+    private CharSequence updateCarrierTextWithSimIoError(CharSequence text, boolean noSims) {
+        final CharSequence carrier = "";
+        CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
+                IccCardConstants.State.CARD_IO_ERROR, carrier);
+        for (int index = 0; index < mSimErrorState.length; index++) {
+            if (mSimErrorState[index]) {
+                // In the case when no sim cards are detected but a faulty card is inserted
+                // overwrite the text and only show "Invalid card"
+                if (noSims) {
+                    return concatenate(carrierTextForSimIOError,
+                            getContext().getText(
+                                    com.android.internal.R.string.emergency_calls_only),
+                            mSeparator);
+                } else if (index == 0) {
+                    // prepend "Invalid card" when faulty card is inserted in slot 0
+                    text = concatenate(carrierTextForSimIOError, text, mSeparator);
+                } else {
+                    // concatenate "Invalid card" when faulty card is inserted in slot 1
+                    text = concatenate(text, carrierTextForSimIOError, mSeparator);
+                }
+            }
+        }
+        return text;
+    }
+
+    /**
+     * Sets the listening status of this controller. If the callback is null, it is set to
+     * not listening
+     *
+     * @param callback Callback to provide text updates
+     */
+    public void setListening(CarrierTextCallback callback) {
+        if (callback != null) {
+            mCarrierTextCallback = callback;
+            if (ConnectivityManager.from(mContext).isNetworkSupported(
+                    ConnectivityManager.TYPE_MOBILE)) {
+                mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+                mKeyguardUpdateMonitor.registerCallback(mCallback);
+                mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+            } else {
+                // Don't listen and clear out the text when the device isn't a phone.
+                mKeyguardUpdateMonitor = null;
+                callback.updateCarrierInfo(new CarrierTextCallbackInfo("", null, false, null));
+            }
+        } else {
+            mCarrierTextCallback = null;
+            if (mKeyguardUpdateMonitor != null) {
+                mKeyguardUpdateMonitor.removeCallback(mCallback);
+                mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
+            }
+        }
+    }
+
+    protected void updateCarrierText() {
+        boolean allSimsMissing = true;
+        boolean anySimReadyAndInService = false;
+        CharSequence displayText = null;
+
+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+        final int numSubs = subs.size();
+        final int[] subsIds = new int[numSubs];
+        if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs);
+        for (int i = 0; i < numSubs; i++) {
+            int subId = subs.get(i).getSubscriptionId();
+            subsIds[i] = subId;
+            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+            CharSequence carrierName = subs.get(i).getCarrierName();
+            CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
+            if (DEBUG) {
+                Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
+            }
+            if (carrierTextForSimState != null) {
+                allSimsMissing = false;
+                displayText = concatenate(displayText, carrierTextForSimState, mSeparator);
+            }
+            if (simState == IccCardConstants.State.READY) {
+                ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
+                if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
+                    // hack for WFC (IWLAN) not turning off immediately once
+                    // Wi-Fi is disassociated or disabled
+                    if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                            || (mWifiManager.isWifiEnabled()
+                            && mWifiManager.getConnectionInfo() != null
+                            && mWifiManager.getConnectionInfo().getBSSID() != null)) {
+                        if (DEBUG) {
+                            Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss);
+                        }
+                        anySimReadyAndInService = true;
+                    }
+                }
+            }
+        }
+        if (allSimsMissing) {
+            if (numSubs != 0) {
+                // Shows "No SIM card | Emergency calls only" on devices that are voice-capable.
+                // This depends on mPlmn containing the text "Emergency calls only" when the radio
+                // has some connectivity. Otherwise, it should be null or empty and just show
+                // "No SIM card"
+                // Grab the first subscripton, because they all should contain the emergency text,
+                // described above.
+                displayText = makeCarrierStringOnEmergencyCapable(
+                        getMissingSimMessage(), subs.get(0).getCarrierName());
+            } else {
+                // We don't have a SubscriptionInfo to get the emergency calls only from.
+                // Grab it from the old sticky broadcast if possible instead. We can use it
+                // here because no subscriptions are active, so we don't have
+                // to worry about MSIM clashing.
+                CharSequence text =
+                        getContext().getText(com.android.internal.R.string.emergency_calls_only);
+                Intent i = getContext().registerReceiver(null,
+                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
+                if (i != null) {
+                    String spn = "";
+                    String plmn = "";
+                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
+                        spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
+                    }
+                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
+                        plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+                    }
+                    if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
+                    if (Objects.equals(plmn, spn)) {
+                        text = plmn;
+                    } else {
+                        text = concatenate(plmn, spn, mSeparator);
+                    }
+                }
+                displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
+            }
+        }
+
+        displayText = updateCarrierTextWithSimIoError(displayText, allSimsMissing);
+        // APM (airplane mode) != no carrier state. There are carrier services
+        // (e.g. WFC = Wi-Fi calling) which may operate in APM.
+        if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
+            displayText = getAirplaneModeMessage();
+        }
+
+        if (mCarrierTextCallback != null) {
+            mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
+                    displayText,
+                    displayText.toString().split(mSeparator.toString()),
+                    anySimReadyAndInService,
+                    subsIds));
+        }
+
+    }
+
+    private Context getContext() {
+        return mContext;
+    }
+
+    private String getMissingSimMessage() {
+        return mShowMissingSim && mTelephonyCapable
+                ? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
+    }
+
+    private String getAirplaneModeMessage() {
+        return mShowAirplaneMode
+                ? getContext().getString(R.string.airplane_mode) : "";
+    }
+
+    /**
+     * Top-level function for creating carrier text. Makes text based on simState, PLMN
+     * and SPN as well as device capabilities, such as being emergency call capable.
+     *
+     * @return Carrier text if not in missing state, null otherwise.
+     */
+    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
+            CharSequence text) {
+        CharSequence carrierText = null;
+        CarrierTextController.StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case Normal:
+                carrierText = text;
+                break;
+
+            case SimNotReady:
+                // Null is reserved for denoting missing, in this case we have nothing to display.
+                carrierText = ""; // nothing to display yet.
+                break;
+
+            case NetworkLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        mContext.getText(R.string.keyguard_network_locked_message), text);
+                break;
+
+            case SimMissing:
+                carrierText = null;
+                break;
+
+            case SimPermDisabled:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(
+                                R.string.keyguard_permanent_disabled_sim_message_short),
+                        text);
+                break;
+
+            case SimMissingLocked:
+                carrierText = null;
+                break;
+
+            case SimLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_locked_message),
+                        text);
+                break;
+
+            case SimPukLocked:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_puk_locked_message),
+                        text);
+                break;
+            case SimIoError:
+                carrierText = makeCarrierStringOnEmergencyCapable(
+                        getContext().getText(R.string.keyguard_sim_error_message_short),
+                        text);
+                break;
+            case SimUnknown:
+                carrierText = null;
+                break;
+        }
+
+        return carrierText;
+    }
+
+    /*
+     * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
+     */
+    private CharSequence makeCarrierStringOnEmergencyCapable(
+            CharSequence simMessage, CharSequence emergencyCallMessage) {
+        if (mIsEmergencyCallCapable) {
+            return concatenate(simMessage, emergencyCallMessage, mSeparator);
+        }
+        return simMessage;
+    }
+
+    /**
+     * Determine the current status of the lock screen given the SIM state and other stuff.
+     */
+    private CarrierTextController.StatusMode getStatusForIccState(IccCardConstants.State simState) {
+        // Since reading the SIM may take a while, we assume it is present until told otherwise.
+        if (simState == null) {
+            return CarrierTextController.StatusMode.Normal;
+        }
+
+        final boolean missingAndNotProvisioned =
+                !KeyguardUpdateMonitor.getInstance(mContext).isDeviceProvisioned()
+                        && (simState == IccCardConstants.State.ABSENT
+                        || simState == IccCardConstants.State.PERM_DISABLED);
+
+        // Assume we're NETWORK_LOCKED if not provisioned
+        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
+        switch (simState) {
+            case ABSENT:
+                return CarrierTextController.StatusMode.SimMissing;
+            case NETWORK_LOCKED:
+                return CarrierTextController.StatusMode.SimMissingLocked;
+            case NOT_READY:
+                return CarrierTextController.StatusMode.SimNotReady;
+            case PIN_REQUIRED:
+                return CarrierTextController.StatusMode.SimLocked;
+            case PUK_REQUIRED:
+                return CarrierTextController.StatusMode.SimPukLocked;
+            case READY:
+                return CarrierTextController.StatusMode.Normal;
+            case PERM_DISABLED:
+                return CarrierTextController.StatusMode.SimPermDisabled;
+            case UNKNOWN:
+                return CarrierTextController.StatusMode.SimUnknown;
+            case CARD_IO_ERROR:
+                return CarrierTextController.StatusMode.SimIoError;
+        }
+        return CarrierTextController.StatusMode.SimUnknown;
+    }
+
+    private static CharSequence concatenate(CharSequence plmn, CharSequence spn,
+            CharSequence separator) {
+        final boolean plmnValid = !TextUtils.isEmpty(plmn);
+        final boolean spnValid = !TextUtils.isEmpty(spn);
+        if (plmnValid && spnValid) {
+            return new StringBuilder().append(plmn).append(separator).append(spn).toString();
+        } else if (plmnValid) {
+            return plmn;
+        } else if (spnValid) {
+            return spn;
+        } else {
+            return "";
+        }
+    }
+
+    private static List<CharSequence> append(List<CharSequence> list, CharSequence string) {
+        if (!TextUtils.isEmpty(string)) {
+            list.add(string);
+        }
+        return list;
+    }
+
+    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
+            String plmn, String spn) {
+        int carrierHelpTextId = 0;
+        CarrierTextController.StatusMode status = getStatusForIccState(simState);
+        switch (status) {
+            case NetworkLocked:
+                carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
+                break;
+
+            case SimMissing:
+                carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
+                break;
+
+            case SimPermDisabled:
+                carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
+                break;
+
+            case SimMissingLocked:
+                carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
+                break;
+
+            case Normal:
+            case SimLocked:
+            case SimPukLocked:
+                break;
+        }
+
+        return mContext.getText(carrierHelpTextId);
+    }
+
+    /**
+     * Data structure for passing information to CarrierTextController subscribers
+     */
+    public static final class CarrierTextCallbackInfo {
+        public final CharSequence carrierText;
+        public final CharSequence[] listOfCarriers;
+        public final boolean anySimReady;
+        public final int[] subscriptionIds;
+
+        CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+                boolean anySimReady, int[] subscriptionIds) {
+            this.carrierText = carrierText;
+            this.listOfCarriers = listOfCarriers;
+            this.anySimReady = anySimReady;
+            this.subscriptionIds = subscriptionIds;
+        }
+    }
+
+    /**
+     * Callback to communicate to Views
+     */
+    public interface CarrierTextCallback {
+        /**
+         * Provides updated carrier information.
+         */
+        default void updateCarrierInfo(CarrierTextCallbackInfo info) {};
+
+        /**
+         * Notifies the View that the device is going to sleep
+         */
+        default void startedGoingToSleep() {};
+
+        /**
+         * Notifies the View that the device finished waking up
+         */
+        default void finishedWakingUp() {};
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d99f234..fece94e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -44,6 +44,7 @@
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.PowerUI;
+import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
@@ -278,6 +279,7 @@
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
     @Inject Lazy<AutoHideController> mAutoHideController;
     @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
+    @Inject Lazy<PrivacyItemController> mPrivacyItemController;
     @Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
     @Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
     @Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
@@ -452,6 +454,8 @@
         mProviders.put(ForegroundServiceNotificationListener.class,
                 mForegroundServiceNotificationListener::get);
         mProviders.put(ClockManager.class, mClockManager::get);
+        mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
+
 
         // TODO(b/118592525): to support multi-display , we start to add something which is
         //                    per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index b218e80..2339fae 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -30,8 +30,12 @@
 import com.android.systemui.appops.AppOpItem
 import com.android.systemui.appops.AppOpsController
 import com.android.systemui.R
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+import javax.inject.Singleton
 
-class PrivacyItemController(val context: Context, val callback: Callback) {
+@Singleton
+class PrivacyItemController @Inject constructor(val context: Context) {
 
     companion object {
         val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
@@ -56,9 +60,10 @@
     private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
     private var listening = false
     val systemApp = PrivacyApplication(context.getString(R.string.device_services), context)
+    private val callbacks = mutableListOf<WeakReference<Callback>>()
 
     private val notifyChanges = Runnable {
-        callback.privacyChanged(privacyList)
+        callbacks.forEach { it.get()?.privacyChanged(privacyList) }
     }
 
     private val updateListAndNotifyChanges = Runnable {
@@ -88,8 +93,8 @@
             registerReceiver()
         }
 
-    init {
-        registerReceiver()
+    private fun unregisterReceiver() {
+        context.unregisterReceiver(userSwitcherReceiver)
     }
 
     private fun registerReceiver() {
@@ -108,17 +113,41 @@
         bgHandler.post(updateListAndNotifyChanges)
     }
 
-    fun setListening(listen: Boolean) {
+    @VisibleForTesting
+    internal fun setListening(listen: Boolean) {
         if (listening == listen) return
         listening = listen
         if (listening) {
             appOpsController.addCallback(OPS, cb)
+            registerReceiver()
             update(true)
         } else {
             appOpsController.removeCallback(OPS, cb)
+            unregisterReceiver()
         }
     }
 
+    private fun addCallback(callback: WeakReference<Callback>) {
+        callbacks.add(callback)
+        if (callbacks.isNotEmpty() && !listening) setListening(true)
+        // Notify this callback if we didn't set to listening
+        else uiHandler.post(NotifyChangesToCallback(callback.get(), privacyList))
+    }
+
+    private fun removeCallback(callback: WeakReference<Callback>) {
+        // Removes also if the callback is null
+        callbacks.removeIf { it.get()?.equals(callback.get()) ?: true }
+        if (callbacks.isEmpty()) setListening(false)
+    }
+
+    fun addCallback(callback: Callback) {
+        addCallback(WeakReference(callback))
+    }
+
+    fun removeCallback(callback: Callback) {
+        removeCallback(WeakReference(callback))
+    }
+
     private fun updatePrivacyList() {
         privacyList = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) }
                 .mapNotNull { toPrivacyItem(it) }.distinct()
@@ -149,4 +178,13 @@
             }
         }
     }
+
+    private class NotifyChangesToCallback(
+        private val callback: Callback?,
+        private val list: List<PrivacyItem>
+    ) : Runnable {
+        override fun run() {
+            callback?.privacyChanged(list)
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index e63f88a..c0ed4b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -30,14 +30,18 @@
 import android.graphics.drawable.RippleDrawable;
 import android.os.Bundle;
 import android.os.UserManager;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -45,7 +49,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.CarrierText;
+import com.android.keyguard.CarrierTextController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.Utils;
 import com.android.settingslib.drawable.UserIconDrawable;
@@ -68,7 +72,11 @@
 import javax.inject.Named;
 
 public class QSFooterImpl extends FrameLayout implements QSFooter,
-        OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback {
+        OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback,
+        CarrierTextController.CarrierTextCallback {
+
+    private static final int SIM_SLOTS = 2;
+    private static final String TAG = "QSFooterImpl";
 
     private final ActivityStarter mActivityStarter;
     private final UserInfoController mUserInfoController;
@@ -77,7 +85,6 @@
     private SettingsButton mSettingsButton;
     protected View mSettingsContainer;
     private PageIndicator mPageIndicator;
-    private CarrierText mCarrierText;
 
     private boolean mQsDisabled;
     private QSPanel mQsPanel;
@@ -99,12 +106,20 @@
 
     private View mActionsContainer;
     private View mDragHandle;
-    private View mMobileGroup;
-    private ImageView mMobileSignal;
-    private ImageView mMobileRoaming;
+
+    private View mCarrierDivider;
+    private ViewGroup mMobileFooter;
+    private View[] mMobileGroups = new View[SIM_SLOTS];
+    private ViewGroup[] mCarrierGroups = new ViewGroup[SIM_SLOTS];
+    private TextView[] mCarrierTexts = new TextView[SIM_SLOTS];
+    private ImageView[] mMobileSignals = new ImageView[SIM_SLOTS];
+    private ImageView[] mMobileRoamings = new ImageView[SIM_SLOTS];
+    private final CellSignalState[] mInfos =
+            new CellSignalState[]{new CellSignalState(), new CellSignalState()};
+
     private final int mColorForeground;
-    private final CellSignalState mInfo = new CellSignalState();
     private OnClickListener mExpandClickListener;
+    private CarrierTextController mCarrierTextController;
 
     @Inject
     public QSFooterImpl(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -134,10 +149,20 @@
         mSettingsContainer = findViewById(R.id.settings_button_container);
         mSettingsButton.setOnClickListener(this);
 
-        mMobileGroup = findViewById(R.id.mobile_combo);
-        mMobileSignal = findViewById(R.id.mobile_signal);
-        mMobileRoaming = findViewById(R.id.mobile_roaming);
-        mCarrierText = findViewById(R.id.qs_carrier_text);
+        mMobileFooter = findViewById(R.id.qs_mobile);
+        mCarrierGroups[0] = findViewById(R.id.carrier1);
+        mCarrierGroups[1] = findViewById(R.id.carrier2);
+
+        for (int i = 0; i < SIM_SLOTS; i++) {
+            mMobileGroups[i] = mCarrierGroups[i].findViewById(R.id.mobile_combo);
+            mMobileSignals[i] = mCarrierGroups[i].findViewById(R.id.mobile_signal);
+            mMobileRoamings[i] = mCarrierGroups[i].findViewById(R.id.mobile_roaming);
+            mCarrierTexts[i] = mCarrierGroups[i].findViewById(R.id.qs_carrier_text);
+        }
+        mCarrierDivider = findViewById(R.id.qs_carrier_divider);
+        CharSequence separator = mContext.getString(
+                com.android.internal.R.string.kg_text_message_separator);
+        mCarrierTextController = new CarrierTextController(mContext, separator, false, false);
 
         mMultiUserSwitch = findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
@@ -204,8 +229,8 @@
     private TouchAnimator createFooterAnimator() {
         return new TouchAnimator.Builder()
                 .addFloat(mDivider, "alpha", 0, 1)
-                .addFloat(mCarrierText, "alpha", 0, 0, 1)
-                .addFloat(mMobileGroup, "alpha", 0, 1)
+                .addFloat(mMobileFooter, "alpha", 0, 0, 1)
+                .addFloat(mCarrierDivider, "alpha", 0, 1)
                 .addFloat(mActionsContainer, "alpha", 0, 1)
                 .addFloat(mDragHandle, "alpha", 1, 0, 0)
                 .addFloat(mPageIndicator, "alpha", 0, 1)
@@ -332,10 +357,12 @@
                 mNetworkController.addEmergencyListener(this);
                 mNetworkController.addCallback(this);
             }
+            mCarrierTextController.setListening(this);
         } else {
             mUserInfoController.removeCallback(this);
             mNetworkController.removeEmergencyListener(this);
             mNetworkController.removeCallback(this);
+            mCarrierTextController.setListening(null);
         }
     }
 
@@ -358,7 +385,8 @@
         if (v == mSettingsButton) {
             if (!mDeviceProvisionedController.isCurrentUserSetup()) {
                 // If user isn't setup just unlock the device and dump them back at SUW.
-                mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
+                mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
+                });
                 return;
             }
             MetricsLogger.action(mContext,
@@ -415,32 +443,64 @@
     }
 
     private void handleUpdateState() {
-        mMobileGroup.setVisibility(mInfo.visible ? View.VISIBLE : View.GONE);
-        if (mInfo.visible) {
-            mMobileRoaming.setVisibility(mInfo.roaming ? View.VISIBLE : View.GONE);
-            mMobileRoaming.setImageTintList(ColorStateList.valueOf(mColorForeground));
-            SignalDrawable d = new SignalDrawable(mContext);
-            d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
-            mMobileSignal.setImageDrawable(d);
-            mMobileSignal.setImageLevel(mInfo.mobileSignalIconId);
+        for (int i = 0; i < SIM_SLOTS; i++) {
+            mMobileGroups[i].setVisibility(mInfos[i].visible ? View.VISIBLE : View.GONE);
+            if (mInfos[i].visible) {
+                mMobileRoamings[i].setVisibility(mInfos[i].roaming ? View.VISIBLE : View.GONE);
+                mMobileRoamings[i].setImageTintList(ColorStateList.valueOf(mColorForeground));
+                SignalDrawable d = new SignalDrawable(mContext);
+                d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
+                mMobileSignals[i].setImageDrawable(d);
+                mMobileSignals[i].setImageLevel(mInfos[i].mobileSignalIconId);
 
-            StringBuilder contentDescription = new StringBuilder();
-            if (mInfo.contentDescription != null) {
-                contentDescription.append(mInfo.contentDescription).append(", ");
+                StringBuilder contentDescription = new StringBuilder();
+                if (mInfos[i].contentDescription != null) {
+                    contentDescription.append(mInfos[i].contentDescription).append(", ");
+                }
+                if (mInfos[i].roaming) {
+                    contentDescription
+                            .append(mContext.getString(R.string.data_connection_roaming))
+                            .append(", ");
+                }
+                // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+                if (TextUtils.equals(mInfos[i].typeContentDescription,
+                        mContext.getString(R.string.data_connection_no_internet))
+                        || TextUtils.equals(mInfos[i].typeContentDescription,
+                        mContext.getString(R.string.cell_data_off_content_description))) {
+                    contentDescription.append(mInfos[i].typeContentDescription);
+                }
+                mMobileSignals[i].setContentDescription(contentDescription);
             }
-            if (mInfo.roaming) {
-                contentDescription
-                        .append(mContext.getString(R.string.data_connection_roaming))
-                        .append(", ");
+        }
+        mCarrierDivider.setVisibility(
+                mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
+        if (info.anySimReady) {
+            boolean[] slotSeen = new boolean[SIM_SLOTS];
+            for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+                int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
+                mInfos[slot].visible = true;
+                slotSeen[slot] = true;
+                mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
+                mCarrierGroups[slot].setVisibility(View.VISIBLE);
             }
-            // TODO: show mobile data off/no internet text for 5 seconds before carrier text
-            if (TextUtils.equals(mInfo.typeContentDescription,
-                    mContext.getString(R.string.data_connection_no_internet))
-                || TextUtils.equals(mInfo.typeContentDescription,
-                    mContext.getString(R.string.cell_data_off_content_description))) {
-                contentDescription.append(mInfo.typeContentDescription);
+            for (int i = 0; i < SIM_SLOTS; i++) {
+                if (!slotSeen[i]) {
+                    mInfos[i].visible = false;
+                    mCarrierGroups[i].setVisibility(View.GONE);
+                }
             }
-            mMobileSignal.setContentDescription(contentDescription);
+            handleUpdateState();
+        } else {
+            mInfos[0].visible = false;
+            mInfos[1].visible = false;
+            mCarrierTexts[0].setText(info.carrierText);
+            mCarrierGroups[0].setVisibility(View.VISIBLE);
+            mCarrierGroups[1].setVisibility(View.GONE);
+            handleUpdateState();
         }
     }
 
@@ -450,18 +510,23 @@
             int qsType, boolean activityIn, boolean activityOut,
             String typeContentDescription,
             String description, boolean isWide, int subId, boolean roaming) {
-        mInfo.visible = statusIcon.visible;
-        mInfo.mobileSignalIconId = statusIcon.icon;
-        mInfo.contentDescription = statusIcon.contentDescription;
-        mInfo.typeContentDescription = typeContentDescription;
-        mInfo.roaming = roaming;
+        int slotIndex = SubscriptionManager.getSlotIndex(subId);
+        if (slotIndex >= SIM_SLOTS) {
+            Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+        }
+        mInfos[slotIndex].visible = statusIcon.visible;
+        mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
+        mInfos[slotIndex].contentDescription = statusIcon.contentDescription;
+        mInfos[slotIndex].typeContentDescription = typeContentDescription;
+        mInfos[slotIndex].roaming = roaming;
         handleUpdateState();
     }
 
     @Override
     public void setNoSims(boolean hasNoSims, boolean simDetected) {
         if (hasNoSims) {
-            mInfo.visible = false;
+            mInfos[0].visible = false;
+            mInfos[1].visible = false;
         }
         handleUpdateState();
     }
@@ -473,4 +538,38 @@
         String typeContentDescription;
         boolean roaming;
     }
+
+
+    /**
+     * TextView that changes its ellipsize value with its visibility.
+     */
+    public static class QSCarrierText extends TextView {
+        public QSCarrierText(Context context) {
+            super(context);
+        }
+
+        public QSCarrierText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+        }
+
+        public QSCarrierText(Context context, AttributeSet attrs, int defStyleAttr,
+                int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+        }
+
+        @Override
+        protected void onVisibilityChanged(View changedView, int visibility) {
+            super.onVisibilityChanged(changedView, visibility);
+            // Only show marquee when visible
+            if (visibility == VISIBLE) {
+                setEllipsize(TextUtils.TruncateAt.MARQUEE);
+            } else {
+                setEllipsize(TextUtils.TruncateAt.END);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 75ab5df..2d64ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -180,14 +180,14 @@
     public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             NextAlarmController nextAlarmController, ZenModeController zenModeController,
             BatteryController batteryController, StatusBarIconController statusBarIconController,
-            ActivityStarter activityStarter) {
+            ActivityStarter activityStarter, PrivacyItemController privacyItemController) {
         super(context, attrs);
         mAlarmController = nextAlarmController;
         mZenController = zenModeController;
         mBatteryController = batteryController;
         mStatusBarIconController = statusBarIconController;
         mActivityStarter = activityStarter;
-        mPrivacyItemController = new PrivacyItemController(context, mPICCallback);
+        mPrivacyItemController = privacyItemController;
         mShownCount = getStoredShownCount();
     }
 
@@ -512,7 +512,6 @@
             return;
         }
         mHeaderQsPanel.setListening(listening);
-        mPrivacyItemController.setListening(listening);
         mListening = listening;
 
         if (listening) {
@@ -520,9 +519,11 @@
             mAlarmController.addCallback(this);
             mContext.registerReceiver(mRingerReceiver,
                     new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+            mPrivacyItemController.addCallback(mPICCallback);
         } else {
             mZenController.removeCallback(this);
             mAlarmController.removeCallback(this);
+            mPrivacyItemController.removeCallback(mPICCallback);
             mContext.unregisterReceiver(mRingerReceiver);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 6c3e504..04534ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -19,6 +19,7 @@
 import android.view.View;
 
 import com.android.systemui.Interpolators;
+import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 /**
@@ -92,9 +93,15 @@
 
     private static void updateLayerType(View view, float alpha) {
         if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) {
-            view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-        } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
-            view.setLayerType(View.LAYER_TYPE_NONE, null);
+            if (view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                view.setTag(R.id.cross_fade_layer_type_changed_tag, true);
+            }
+        } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE
+                && view.getTag(R.id.cross_fade_layer_type_changed_tag) != null) {
+            if (view.getTag(R.id.cross_fade_layer_type_changed_tag) != null) {
+                view.setLayerType(View.LAYER_TYPE_NONE, null);
+            }
         }
     }
 
@@ -114,7 +121,7 @@
                 .setStartDelay(delay)
                 .setInterpolator(Interpolators.ALPHA_IN)
                 .withEndAction(null);
-        if (view.hasOverlappingRendering()) {
+        if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
             view.animate().withLayer();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
new file mode 100644
index 0000000..4944732
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar
+
+import android.annotation.ColorInt
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Point
+import android.graphics.Rect
+import android.renderscript.Allocation
+import android.renderscript.Element
+import android.renderscript.RenderScript
+import android.renderscript.ScriptIntrinsicBlur
+import android.util.MathUtils
+import com.android.internal.graphics.ColorUtils
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val COLOR_ALPHA = (255 * 0.7f).toInt()
+private const val BLUR_RADIUS = 25f
+private const val DOWNSAMPLE = 6
+
+@Singleton
+class MediaArtworkProcessor @Inject constructor() {
+
+    private val mTmpSize = Point()
+    private var mArtworkCache: Bitmap? = null
+
+    fun processArtwork(context: Context, artwork: Bitmap, @ColorInt color: Int): Bitmap {
+        if (mArtworkCache != null) {
+            return mArtworkCache!!
+        }
+
+        context.display.getSize(mTmpSize)
+        val renderScript = RenderScript.create(context)
+        val rect = Rect(0, 0,artwork.width, artwork.height)
+        MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
+        val inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
+                true /* filter */)
+        val input = Allocation.createFromBitmap(renderScript, inBitmap,
+                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE)
+        val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height,
+                Bitmap.Config.ARGB_8888)
+        val output = Allocation.createFromBitmap(renderScript, outBitmap)
+        val blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
+        blur.setRadius(BLUR_RADIUS)
+        blur.setInput(input)
+        blur.forEach(output)
+        output.copyTo(outBitmap)
+
+        input.destroy()
+        output.destroy()
+        inBitmap.recycle()
+
+        val canvas = Canvas(outBitmap)
+        canvas.drawColor(ColorUtils.setAlphaComponent(color, COLOR_ALPHA))
+        return outBitmap
+    }
+
+    fun clearCache() {
+        mArtworkCache?.recycle()
+        mArtworkCache = null
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index f46ded4d..c25b7cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -39,6 +39,9 @@
 
     boolean isCurrentProfile(int userId);
 
+    /** Adds a listener to be notified when the current user changes. */
+    void addUserChangedListener(UserChangedListener listener);
+
     void destroy();
 
     SparseArray<UserInfo> getCurrentProfiles();
@@ -58,4 +61,9 @@
     boolean needsRedaction(NotificationEntry entry);
 
     boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
+
+    /** Notified when the current user changes. */
+    interface UserChangedListener {
+        void onUserChanged(int userId);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index d2ce31d..4f9d428 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -55,6 +55,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Handles keeping track of the current user, profiles, and various things related to hiding
@@ -78,6 +80,7 @@
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
     private final UserManager mUserManager;
     private final IStatusBarService mBarService;
+    private final List<UserChangedListener> mListeners = new ArrayList<>();
 
     private boolean mShowLockscreenNotifications;
     private boolean mAllowLockscreenRemoteInput;
@@ -112,6 +115,10 @@
                 updatePublicMode();
                 mPresenter.onUserSwitched(mCurrentUserId);
                 getEntryManager().getNotificationData().filterAndSort();
+
+                for (UserChangedListener listener : mListeners) {
+                    listener.onUserChanged(mCurrentUserId);
+                }
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 updateCurrentProfilesCache();
             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
@@ -502,6 +509,10 @@
         }
     }
 
+    @Override
+    public void addUserChangedListener(UserChangedListener listener) {
+        mListeners.add(listener);
+    }
 
 //    public void updatePublicMode() {
 //        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
@@ -541,6 +552,7 @@
     public void destroy() {
         mContext.unregisterReceiver(mBaseBroadcastReceiver);
         mContext.unregisterReceiver(mAllUsersReceiver);
+        mListeners.clear();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 7412702..98a3a54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -25,6 +25,7 @@
 import android.app.Notification;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -102,6 +103,7 @@
     private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
     private final ArrayList<MediaListener> mMediaListeners;
+    private final MediaArtworkProcessor mMediaArtworkProcessor;
 
     protected NotificationPresenter mPresenter;
     private MediaController mMediaController;
@@ -133,6 +135,7 @@
             if (DEBUG_MEDIA) {
                 Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
             }
+            mMediaArtworkProcessor.clearCache();
             mMediaMetadata = metadata;
             dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
         }
@@ -143,8 +146,10 @@
             Context context,
             Lazy<ShadeController> shadeController,
             Lazy<StatusBarWindowController> statusBarWindowController,
-            NotificationEntryManager notificationEntryManager) {
+            NotificationEntryManager notificationEntryManager,
+            MediaArtworkProcessor mediaArtworkProcessor) {
         mContext = context;
+        mMediaArtworkProcessor = mediaArtworkProcessor;
         mMediaListeners = new ArrayList<>();
         mMediaSessionManager
                 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -366,6 +371,7 @@
     }
 
     private void clearCurrentMediaNotificationSession() {
+        mMediaArtworkProcessor.clearCache();
         mMediaMetadata = null;
         if (mMediaController != null) {
             if (DEBUG_MEDIA) {
@@ -418,7 +424,19 @@
                 // might still be null
             }
             if (artworkBitmap != null) {
-                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
+                int notificationColor;
+                synchronized (mEntryManager.getNotificationData()) {
+                    NotificationEntry entry = mEntryManager.getNotificationData()
+                            .get(mMediaNotificationKey);
+                    if (entry == null || entry.getRow() == null) {
+                        notificationColor = Color.TRANSPARENT;
+                    } else {
+                        notificationColor = entry.getRow().calculateBgColor();
+                    }
+                }
+                Bitmap bmp = mMediaArtworkProcessor.processArtwork(mContext, artworkBitmap,
+                        notificationColor);
+                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), bmp);
             }
         }
         boolean allowWhenShade = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 8c29fb5..54ed0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -333,6 +333,7 @@
                         mGroupManager.onEntryUpdated(entry, oldSbn);
                     }
                     entry.populateFromRanking(mTmpRanking);
+                    entry.setIsHighPriority(isHighPriority(entry.notification));
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index ee551ee..2e93c382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -153,6 +153,12 @@
      */
     private boolean mUserDismissedBubble;
 
+    /**
+     * Whether this notification is shown to the user as a high priority notification: visible on
+     * the lock screen/status bar and in the top section in the shade.
+     */
+    private boolean mHighPriority;
+
     public NotificationEntry(StatusBarNotification n) {
         this(n, null);
     }
@@ -191,6 +197,14 @@
         return interruption;
     }
 
+    public boolean isHighPriority() {
+        return mHighPriority;
+    }
+
+    public void setIsHighPriority(boolean highPriority) {
+        this.mHighPriority = highPriority;
+    }
+
     public void setIsBubble(boolean bubbleable) {
         mIsBubble = bubbleable;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 7b94c74..35b7ef4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -167,13 +167,10 @@
      */
     public static NotificationVisibility.NotificationLocation getNotificationLocation(
             NotificationEntry entry) {
-        ExpandableNotificationRow row = entry.getRow();
-        ExpandableViewState childViewState = row.getViewState();
-
-        if (childViewState == null) {
+        if (entry == null || entry.getRow() == null || entry.getRow().getViewState() == null) {
             return NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN;
         }
-        return convertNotificationLocation(childViewState.location);
+        return convertNotificationLocation(entry.getRow().getViewState().location);
     }
 
     private static NotificationVisibility.NotificationLocation convertNotificationLocation(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 296c061..bed2426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3092,6 +3092,11 @@
         }
     }
 
+    /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
+    public void setDismissRtl(boolean dismissRtl) {
+        mMenuRow.setDismissRtl(dismissRtl);
+    }
+
     private static class NotificationViewState extends ExpandableViewState {
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 5e9f207..cb1384c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -300,7 +300,8 @@
                 row.getIsNonblockable(),
                 isForBlockingHelper,
                 row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE,
-                row.getEntry().importance);
+                row.getEntry().importance,
+                row.getEntry().isHighPriority());
 
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 5253e38..2a9a815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -21,7 +21,6 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -97,8 +96,12 @@
     private int mNumUniqueChannelsInRow;
     private NotificationChannel mSingleNotificationChannel;
     private int mStartingChannelImportance;
-    private int mStartingChannelOrNotificationImportance;
-    private int mChosenImportance;
+    private boolean mWasShownHighPriority;
+    /**
+     * The last importance level chosen by the user.  Null if the user has not chosen an importance
+     * level; non-null once the user takes an action which indicates an explicit preference.
+     */
+    @Nullable private Integer mChosenImportance;
     private boolean mIsSingleDefaultChannel;
     private boolean mIsNonblockable;
     private StatusBarNotification mSbn;
@@ -195,13 +198,14 @@
             final OnAppSettingsClickListener onAppSettingsClick,
             boolean isDeviceProvisioned,
             boolean isNonblockable,
-            int importance)
+            int importance,
+            boolean wasShownHighPriority)
             throws RemoteException {
         bindNotification(pm, iNotificationManager, pkg, notificationChannel,
                 numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
                 onAppSettingsClick, isDeviceProvisioned, isNonblockable,
                 false /* isBlockingHelper */, false /* isUserSentimentNegative */,
-                importance);
+                importance, wasShownHighPriority);
     }
 
     public void bindNotification(
@@ -218,7 +222,8 @@
             boolean isNonblockable,
             boolean isForBlockingHelper,
             boolean isUserSentimentNegative,
-            int importance)
+            int importance,
+            boolean wasShownHighPriority)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
         mMetricsLogger = Dependency.get(MetricsLogger.class);
@@ -231,10 +236,8 @@
         mCheckSaveListener = checkSaveListener;
         mOnSettingsClickListener = onSettingsClick;
         mSingleNotificationChannel = notificationChannel;
-        int channelImportance = mSingleNotificationChannel.getImportance();
-        mStartingChannelImportance = mChosenImportance = channelImportance;
-        mStartingChannelOrNotificationImportance =
-                channelImportance == IMPORTANCE_UNSPECIFIED ? importance : channelImportance;
+        mStartingChannelImportance = mSingleNotificationChannel.getImportance();
+        mWasShownHighPriority = wasShownHighPriority;
         mNegativeUserSentiment = isUserSentimentNegative;
         mIsNonblockable = isNonblockable;
         mIsForeground =
@@ -400,19 +403,27 @@
      * @return new LogMaker
      */
     private LogMaker importanceChangeLogMaker() {
+        Integer chosenImportance =
+                mChosenImportance != null ? mChosenImportance : mStartingChannelImportance;
         return new LogMaker(MetricsEvent.ACTION_SAVE_IMPORTANCE)
                 .setType(MetricsEvent.TYPE_ACTION)
-                .setSubtype(mChosenImportance - mStartingChannelImportance);
+                .setSubtype(chosenImportance - mStartingChannelImportance);
     }
 
     private boolean hasImportanceChanged() {
         return mSingleNotificationChannel != null
-                && mStartingChannelImportance != mChosenImportance;
+                && mChosenImportance != null
+                && (mStartingChannelImportance != mChosenImportance
+                || (mWasShownHighPriority && mChosenImportance < IMPORTANCE_DEFAULT)
+                || (!mWasShownHighPriority && mChosenImportance >= IMPORTANCE_DEFAULT));
     }
 
     private void saveImportance() {
         if (!mIsNonblockable
                 || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
+            if (mChosenImportance == null) {
+                mChosenImportance = mStartingChannelImportance;
+            }
             updateImportance();
         }
     }
@@ -421,12 +432,15 @@
      * Commits the updated importance values on the background thread.
      */
     private void updateImportance() {
-        mMetricsLogger.write(importanceChangeLogMaker());
+        if (mChosenImportance != null) {
+            mMetricsLogger.write(importanceChangeLogMaker());
 
-        Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
-        bgHandler.post(new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
-                mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
-                mStartingChannelImportance, mChosenImportance));
+            Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
+            bgHandler.post(
+                    new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
+                            mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
+                            mStartingChannelImportance, mChosenImportance));
+        }
     }
 
     private void bindButtons() {
@@ -444,11 +458,8 @@
             TextView silent = findViewById(R.id.int_silent);
             TextView alert = findViewById(R.id.int_alert);
 
-            boolean isCurrentlyAlerting =
-                    mStartingChannelOrNotificationImportance >= IMPORTANCE_DEFAULT;
-
             block.setOnClickListener(mOnStopOrMinimizeNotifications);
-            if (isCurrentlyAlerting) {
+            if (mWasShownHighPriority) {
                 silent.setOnClickListener(mOnToggleSilent);
                 silent.setText(R.string.inline_silent_button_silent);
                 alert.setOnClickListener(mOnKeepShowing);
@@ -517,7 +528,7 @@
                 break;
             case ACTION_TOGGLE_SILENT:
                 mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
-                if (mStartingChannelOrNotificationImportance >= IMPORTANCE_DEFAULT) {
+                if (mWasShownHighPriority) {
                     mChosenImportance = IMPORTANCE_LOW;
                     confirmationText.setText(R.string.notification_channel_silenced);
                 } else {
@@ -584,9 +595,8 @@
 
     @Override
     public void onFinishedClosing() {
-        mStartingChannelImportance = mChosenImportance;
-        if (mChosenImportance != IMPORTANCE_UNSPECIFIED) {
-            mStartingChannelOrNotificationImportance = mChosenImportance;
+        if (mChosenImportance != null) {
+            mStartingChannelImportance = mChosenImportance;
         }
         mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index d97162c..d83a158 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -23,7 +23,6 @@
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -78,6 +77,8 @@
     private ArrayList<MenuItem> mRightMenuItems;
     private final Map<View, MenuItem> mMenuItemsByView = new ArrayMap<>();
     private OnMenuEventListener mMenuListener;
+    private boolean mDismissRtl;
+    private boolean mIsForeground;
 
     private ValueAnimator mFadeAnimator;
     private boolean mAnimating;
@@ -238,6 +239,8 @@
     }
 
     private void createMenuViews(boolean resetState, final boolean isForeground) {
+        mIsForeground = isForeground;
+
         final Resources res = mContext.getResources();
         mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
         mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
@@ -250,12 +253,7 @@
         }
         mAppOpsItem = createAppOpsItem(mContext);
         if (NotificationUtils.useNewInterruptionModel(mContext)) {
-            int channelImportance = mParent.getEntry().channel.getImportance();
-            int effectiveImportance =
-                    channelImportance == NotificationManager.IMPORTANCE_UNSPECIFIED
-                            ? mParent.getEntry().importance : channelImportance;
-            mInfoItem = createInfoItem(mContext,
-                    effectiveImportance < NotificationManager.IMPORTANCE_DEFAULT);
+            mInfoItem = createInfoItem(mContext, !mParent.getEntry().isHighPriority());
         } else {
             mInfoItem = createInfoItem(mContext);
         }
@@ -268,10 +266,11 @@
             mRightMenuItems.add(mAppOpsItem);
             mLeftMenuItems.addAll(mRightMenuItems);
         } else {
-            mRightMenuItems.add(mInfoItem);
-            mRightMenuItems.add(mAppOpsItem);
+            ArrayList<MenuItem> menuItems = mDismissRtl ? mLeftMenuItems : mRightMenuItems;
+            menuItems.add(mInfoItem);
+            menuItems.add(mAppOpsItem);
             if (!isForeground) {
-                mRightMenuItems.add(mSnoozeItem);
+                menuItems.add(mSnoozeItem);
             }
         }
 
@@ -729,6 +728,14 @@
         return getParent().canViewBeDismissed();
     }
 
+    @Override
+    public void setDismissRtl(boolean dismissRtl) {
+        mDismissRtl = dismissRtl;
+        if (mMenuContainer != null) {
+            createMenuViews(true, mIsForeground);
+        }
+    }
+
     public static class NotificationMenuItem implements MenuItem {
         View mMenuView;
         GutsContent mGutsContent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
index db7b4fc..4bdc170 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
@@ -17,8 +17,15 @@
 package com.android.systemui.statusbar.notification.row.wrapper;
 
 import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.os.Build;
 import android.view.View;
 
+import com.android.internal.graphics.ColorUtils;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
@@ -42,6 +49,47 @@
     }
 
     @Override
+    public void onReinflated() {
+        super.onReinflated();
+
+        Configuration configuration = mView.getResources().getConfiguration();
+        boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+
+        float[] hsl = new float[] {0f, 0f, 0f};
+        ColorUtils.colorToHSL(mBackgroundColor, hsl);
+        boolean backgroundIsDark = Color.alpha(mBackgroundColor) == 0
+                || hsl[1] == 0 && hsl[2] < 0.5;
+        boolean backgroundHasColor = hsl[1] > 0;
+
+        // Let's invert the notification colors when we're in night mode and
+        // the notification background isn't colorized.
+        if (!backgroundIsDark && !backgroundHasColor && nightMode
+                && mRow.getEntry().targetSdk < Build.VERSION_CODES.Q) {
+            Paint paint = new Paint();
+            ColorMatrix matrix = new ColorMatrix();
+            ColorMatrix tmp = new ColorMatrix();
+            // Inversion should happen on Y'UV space to conseve the colors and
+            // only affect the luminosity.
+            matrix.setRGB2YUV();
+            tmp.set(new float[]{
+                    -1f, 0f, 0f, 0f, 255f,
+                    0f, 1f, 0f, 0f, 0f,
+                    0f, 0f, 1f, 0f, 0f,
+                    0f, 0f, 0f, 1f, 0f
+            });
+            matrix.postConcat(tmp);
+            tmp.setYUV2RGB();
+            matrix.postConcat(tmp);
+            paint.setColorFilter(new ColorMatrixColorFilter(matrix));
+            mView.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+
+            hsl[2] = 1f - hsl[2];
+            mBackgroundColor = ColorUtils.HSLToColor(hsl);
+        }
+    }
+
+    @Override
     protected boolean shouldClearBackgroundOnReapply() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 1efdc56..9258c99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -37,7 +37,7 @@
     protected final View mView;
     protected final ExpandableNotificationRow mRow;
 
-    private int mBackgroundColor = 0;
+    protected int mBackgroundColor = 0;
 
     public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2129b81..63b34d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -174,6 +174,7 @@
     private final boolean mShouldDrawNotificationBackground;
     private boolean mLowPriorityBeforeSpeedBump;
     private final boolean mAllowLongPress;
+    private boolean mDismissRtl;
 
     private float mExpandedHeight;
     private int mOwnScrollY;
@@ -533,8 +534,10 @@
         tunerService.addTunable((key, newValue) -> {
             if (key.equals(LOW_PRIORITY)) {
                 mLowPriorityBeforeSpeedBump = "1".equals(newValue);
+            } else if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) {
+                updateDismissRtlSetting("1".equals(newValue));
             }
-        }, LOW_PRIORITY);
+        }, LOW_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL);
 
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -548,6 +551,16 @@
         });
     }
 
+    private void updateDismissRtlSetting(boolean dismissRtl) {
+        mDismissRtl = dismissRtl;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof ExpandableNotificationRow) {
+                ((ExpandableNotificationRow) child).setDismissRtl(dismissRtl);
+            }
+        }
+    }
+
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onFinishInflate() {
@@ -2600,8 +2613,7 @@
             View child = getChildAt(i);
             if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!mEntryManager.getNotificationData().isHighPriority(
-                        row.getStatusBarNotification())) {
+                if (!row.getEntry().isHighPriority()) {
                     break;
                 } else {
                     lastChildBeforeGap = row;
@@ -2619,8 +2631,7 @@
             View child = getChildAt(i);
             if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!mEntryManager.getNotificationData().isHighPriority(
-                        row.getStatusBarNotification())) {
+                if (!row.getEntry().isHighPriority()) {
                     return row;
                 }
             }
@@ -3255,6 +3266,9 @@
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
         updateChronometerForChild(child);
+        if (child instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) child).setDismissRtl(mDismissRtl);
+        }
         if (ANCHOR_SCROLLING) {
             // TODO: once we're recycling this will need to check the adapter position of the child
             if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
@@ -5756,11 +5770,9 @@
             currentIndex++;
             boolean beforeSpeedBump;
             if (mLowPriorityBeforeSpeedBump) {
-                beforeSpeedBump = !mEntryManager.getNotificationData().isAmbient(
-                        row.getStatusBarNotification().getKey());
+                beforeSpeedBump = !row.getEntry().ambient;
             } else {
-                beforeSpeedBump = mEntryManager.getNotificationData().isHighPriority(
-                        row.getStatusBarNotification());
+                beforeSpeedBump = row.getEntry().isHighPriority();
             }
             if (beforeSpeedBump) {
                 speedBumpIndex = currentIndex;
@@ -5784,8 +5796,7 @@
                     continue;
                 }
                 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                if (!mEntryManager.getNotificationData().isHighPriority(
-                        row.getStatusBarNotification())) {
+                if (!row.getEntry().isHighPriority()) {
                     if (currentIndex > 0) {
                         gapIndex = currentIndex;
                     }
@@ -6315,7 +6326,7 @@
         public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
             boolean isValidDirection;
             if (NotificationUtils.useNewInterruptionModel(mContext)) {
-                isValidDirection = isLayoutRtl() ? !isRightOrDown : isRightOrDown;
+                isValidDirection = mDismissRtl ? !isRightOrDown : isRightOrDown;
             } else {
                 isValidDirection = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index a5d9382..39fbbb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
 
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.statusbar.phone.NavigationPrototypeController.PROTOTYPE_ENABLED;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -84,7 +85,7 @@
 
         // Tell launcher that this action requires a stable task list or not
         boolean flag = requiresStableTaskList();
-        if (flag != sLastTaskStabilizationFlag) {
+        if (getGlobalBoolean(PROTOTYPE_ENABLED) && flag != sLastTaskStabilizationFlag) {
             Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
                     ENABLE_TASK_STABILIZER_FLAG, flag ? 1 : 0);
             sLastTaskStabilizationFlag = flag;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index a09e585..f762a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -37,6 +37,7 @@
 
     private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
     public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
+    public static final String PROTOTYPE_ENABLED = "prototype_enabled";
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 077fcda..e86996a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -194,8 +194,7 @@
         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
             return false;
         }
-        if (!showLowPriority
-                && !mEntryManager.getNotificationData().isHighPriority(entry.notification)) {
+        if (!showLowPriority && !entry.isHighPriority()) {
             return false;
         }
         if (!entry.isTopLevelChild()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 43c35f1..18711c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -173,7 +173,7 @@
         mProvisionedController = Dependency.get(DeviceProvisionedController.class);
         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
         mLocationController = Dependency.get(LocationController.class);
-        mPrivacyItemController = new PrivacyItemController(mContext, this);
+        mPrivacyItemController = Dependency.get(PrivacyItemController.class);
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -266,7 +266,7 @@
         mNextAlarmController.addCallback(mNextAlarmCallback);
         mDataSaver.addCallback(this);
         mKeyguardMonitor.addCallback(this);
-        mPrivacyItemController.setListening(true);
+        mPrivacyItemController.addCallback(this);
 
         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
@@ -294,7 +294,7 @@
         mNextAlarmController.removeCallback(mNextAlarmCallback);
         mDataSaver.removeCallback(this);
         mKeyguardMonitor.removeCallback(this);
-        mPrivacyItemController.setListening(false);
+        mPrivacyItemController.removeCallback(this);
         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
         mContext.unregisterReceiver(mIntentReceiver);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index e6d7ee7..98bf3c27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -45,9 +45,12 @@
 import org.mockito.Mock
 import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
@@ -73,6 +76,8 @@
     private lateinit var userManager: UserManager
     @Captor
     private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
+    @Captor
+    private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback>
 
     private lateinit var testableLooper: TestableLooper
     private lateinit var privacyItemController: PrivacyItemController
@@ -95,7 +100,16 @@
             }
         })).`when`(userManager).getProfiles(anyInt())
 
-        privacyItemController = PrivacyItemController(mContext, callback)
+        privacyItemController = PrivacyItemController(mContext)
+    }
+
+    @Test
+    fun testSetListeningTrueByAddingCallback() {
+        privacyItemController.addCallback(callback)
+        verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
+                any(AppOpsController.Callback::class.java))
+        testableLooper.processAllMessages()
+        verify(callback).privacyChanged(anyList())
     }
 
     @Test
@@ -103,8 +117,6 @@
         privacyItemController.setListening(true)
         verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
                 any(AppOpsController.Callback::class.java))
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(anyList())
     }
 
     @Test
@@ -121,7 +133,7 @@
                 AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1)))
                 .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
 
-        privacyItemController.setListening(true)
+        privacyItemController.addCallback(callback)
         testableLooper.processAllMessages()
         verify(callback).privacyChanged(capture(argCaptor))
         assertEquals(1, argCaptor.value.size)
@@ -131,7 +143,7 @@
     fun testSystemApps() {
         doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, SYSTEM_UID, TEST_PACKAGE_NAME,
                 0))).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-        privacyItemController.setListening(true)
+        privacyItemController.addCallback(callback)
         testableLooper.processAllMessages()
         verify(callback).privacyChanged(capture(argCaptor))
         assertEquals(1, argCaptor.value.size)
@@ -142,8 +154,8 @@
     @Test
     fun testRegisterReceiver_allUsers() {
         val spiedContext = spy(mContext)
-        val itemController = PrivacyItemController(spiedContext, callback)
-
+        val itemController = PrivacyItemController(spiedContext)
+        itemController.setListening(true)
         verify(spiedContext, atLeastOnce()).registerReceiverAsUser(
                 eq(itemController.userSwitcherReceiver), eq(UserHandle.ALL), any(), eq(null),
                 eq(null))
@@ -170,4 +182,54 @@
                 Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED))
         verify(userManager).getProfiles(anyInt())
     }
+
+    @Test
+    fun testAddMultipleCallbacks() {
+        val otherCallback = mock(PrivacyItemController.Callback::class.java)
+        privacyItemController.addCallback(callback)
+        testableLooper.processAllMessages()
+        verify(callback).privacyChanged(anyList())
+
+        privacyItemController.addCallback(otherCallback)
+        testableLooper.processAllMessages()
+        verify(otherCallback).privacyChanged(anyList())
+        // Adding a callback should not unnecessarily call previous ones
+        verifyNoMoreInteractions(callback)
+    }
+
+    @Test
+    fun testMultipleCallbacksAreUpdated() {
+        doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+        val otherCallback = mock(PrivacyItemController.Callback::class.java)
+        privacyItemController.addCallback(callback)
+        privacyItemController.addCallback(otherCallback)
+        testableLooper.processAllMessages()
+        reset(callback)
+        reset(otherCallback)
+
+        verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
+        argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
+        testableLooper.processAllMessages()
+        verify(callback).privacyChanged(anyList())
+        verify(otherCallback).privacyChanged(anyList())
+    }
+
+    @Test
+    fun testRemoveCallback() {
+        doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+        val otherCallback = mock(PrivacyItemController.Callback::class.java)
+        privacyItemController.addCallback(callback)
+        privacyItemController.addCallback(otherCallback)
+        testableLooper.processAllMessages()
+        reset(callback)
+        reset(otherCallback)
+
+        verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
+        privacyItemController.removeCallback(callback)
+        argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
+        testableLooper.processAllMessages()
+        verify(callback, never()).privacyChanged(anyList())
+        verify(otherCallback).privacyChanged(anyList())
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 40d2da9..fdc9e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -354,7 +354,8 @@
                 eq(false),
                 eq(true) /* isForBlockingHelper */,
                 eq(true) /* isUserSentimentNegative */,
-                eq(0));
+                eq(0),
+                eq(false) /* wasShownHighPriority */);
     }
 
     @Test
@@ -382,16 +383,18 @@
                 eq(false),
                 eq(false) /* isForBlockingHelper */,
                 eq(true) /* isUserSentimentNegative */,
-                eq(0));
+                eq(0),
+                eq(false) /* wasShownHighPriority */);
     }
 
     @Test
-    public void testInitializeNotificationInfoView_importance() throws Exception {
+    public void testInitializeNotificationInfoView_highPriority() throws Exception {
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
         row.setBlockingHelperShowing(true);
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
         row.getEntry().importance = IMPORTANCE_DEFAULT;
+        row.getEntry().setIsHighPriority(true);
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
 
@@ -411,7 +414,8 @@
                 eq(false),
                 eq(true) /* isForBlockingHelper */,
                 eq(true) /* isUserSentimentNegative */,
-                eq(IMPORTANCE_DEFAULT));
+                eq(IMPORTANCE_DEFAULT),
+                eq(true) /* wasShownHighPriority */);
     }
 
     @Test
@@ -440,7 +444,8 @@
                 eq(false),
                 eq(false) /* isForBlockingHelper */,
                 eq(true) /* isUserSentimentNegative */,
-                eq(0));
+                eq(0),
+                eq(false) /* wasShownHighPriority */);
     }
 
     @Test
@@ -468,7 +473,8 @@
                 eq(false),
                 eq(true) /* isForBlockingHelper */,
                 eq(true) /* isUserSentimentNegative */,
-                eq(0));
+                eq(0),
+                eq(false) /* wasShownHighPriority */);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index f6791dd5..08955e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -210,7 +210,7 @@
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
         assertTrue(textView.getText().toString().contains("App Name"));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -223,7 +223,7 @@
                 .thenReturn(iconDrawable);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
@@ -232,7 +232,7 @@
     public void testBindNotification_noDelegate() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(GONE, nameView.getVisibility());
         final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
@@ -251,7 +251,7 @@
 
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(VISIBLE, nameView.getVisibility());
         assertTrue(nameView.getText().toString().contains("Other"));
@@ -263,7 +263,7 @@
     public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(GONE, groupNameView.getVisibility());
         final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
@@ -280,7 +280,7 @@
                 .thenReturn(notificationChannelGroup);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(View.VISIBLE, groupNameView.getVisibility());
         assertEquals("Test Group Name", groupNameView.getText());
@@ -292,7 +292,7 @@
     public void testBindNotification_SetsTextChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(TEST_CHANNEL_NAME, textView.getText());
     }
@@ -301,7 +301,7 @@
     public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
-                false, IMPORTANCE_DEFAULT);
+                false, IMPORTANCE_DEFAULT, true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(GONE, textView.getVisibility());
     }
@@ -314,7 +314,7 @@
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
-                false, IMPORTANCE_DEFAULT);
+                false, IMPORTANCE_DEFAULT, true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
     }
@@ -323,7 +323,7 @@
     public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
     }
@@ -332,7 +332,7 @@
     public void testBindNotification_BlockButton() throws Exception {
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-               IMPORTANCE_DEFAULT);
+               IMPORTANCE_DEFAULT, true);
         final View block = mNotificationInfo.findViewById(R.id.int_block);
         final View minimize = mNotificationInfo.findViewById(R.id.block_or_minimize);
         assertEquals(VISIBLE, block.getVisibility());
@@ -343,7 +343,7 @@
     public void testBindNotification_BlockButton_BlockHelper() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT);
+                true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT, true);
         final View block = mNotificationInfo.findViewById(R.id.block);
         final View interruptivenessSettings = mNotificationInfo.findViewById(
                 R.id.interruptiveness_settings);
@@ -356,7 +356,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
         assertEquals(VISIBLE, silent.getVisibility());
         assertEquals(
@@ -368,7 +368,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_LOW);
+                IMPORTANCE_LOW, false);
         final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
         assertEquals(VISIBLE, silent.getVisibility());
         assertEquals(
@@ -381,7 +381,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_LOW);
+                IMPORTANCE_LOW, false);
         final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
         assertEquals(VISIBLE, alert.getVisibility());
         assertEquals(
@@ -393,7 +393,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
         assertEquals(VISIBLE, alert.getVisibility());
         assertEquals(
@@ -405,7 +405,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
         final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
         assertEquals(VISIBLE, silent.getVisibility());
@@ -421,7 +421,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_LOW);
+                IMPORTANCE_LOW, false);
         final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
         final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
         assertEquals(VISIBLE, silent.getVisibility());
@@ -437,7 +437,7 @@
         mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final View block = mNotificationInfo.findViewById(R.id.block);
         final View interruptivenessSettings = mNotificationInfo.findViewById(
                 R.id.interruptiveness_settings);
@@ -455,7 +455,7 @@
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                     latch.countDown();
-                }, null, true, false, IMPORTANCE_DEFAULT);
+                }, null, true, false, IMPORTANCE_DEFAULT, true);
 
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         settingsButton.performClick();
@@ -467,7 +467,7 @@
     public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -479,7 +479,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
-                }, null, false, false, IMPORTANCE_DEFAULT);
+                }, null, false, false, IMPORTANCE_DEFAULT, true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -488,11 +488,11 @@
     public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
                 (View v, NotificationChannel c, int appUid) -> {
-                }, null, true, false, IMPORTANCE_DEFAULT);
+                }, null, true, false, IMPORTANCE_DEFAULT, true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertEquals(View.VISIBLE, settingsButton.getVisibility());
     }
@@ -501,7 +501,7 @@
     public void testLogBlockingHelperCounter_logGutsViewDisplayed() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
         verify(mMetricsLogger).write(argThat(logMaker ->
                 logMaker.getType() == MetricsEvent.NOTIFICATION_BLOCKING_HELPER
@@ -513,7 +513,7 @@
     public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
-                true, true, IMPORTANCE_DEFAULT);
+                true, true, IMPORTANCE_DEFAULT, true);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
         verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
     }
@@ -526,7 +526,7 @@
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(null, c);
                     latch.countDown();
-                }, null, true, true, IMPORTANCE_DEFAULT);
+                }, null, true, true, IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.info).performClick();
         // Verify that listener was triggered.
@@ -539,7 +539,7 @@
             throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
-                null, true, true, IMPORTANCE_DEFAULT);
+                null, true, true, IMPORTANCE_DEFAULT, true);
         final TextView channelNameView =
                 mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(GONE, channelNameView.getVisibility());
@@ -550,7 +550,7 @@
     public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
-                null, true, true, IMPORTANCE_DEFAULT);
+                null, true, true, IMPORTANCE_DEFAULT, true);
         final TextView blockView = mNotificationInfo.findViewById(R.id.block);
         assertEquals(GONE, blockView.getVisibility());
     }
@@ -559,7 +559,7 @@
     public void testbindNotification_BlockingHelper() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false,
-                true, true, IMPORTANCE_DEFAULT);
+                true, true, IMPORTANCE_DEFAULT, true);
         final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
         assertEquals(View.VISIBLE, view.getVisibility());
         assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
@@ -569,7 +569,7 @@
     public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
         assertEquals(View.VISIBLE, view.getVisibility());
         assertEquals(mContext.getString(R.string.notification_unblockable_desc),
@@ -580,7 +580,7 @@
     public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         mTestableLooper.processAllMessages();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), eq(TEST_UID), any());
@@ -591,7 +591,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         mTestableLooper.processAllMessages();
@@ -605,7 +605,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         mTestableLooper.processAllMessages();
@@ -619,7 +619,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.int_silent).performClick();
         mTestableLooper.processAllMessages();
@@ -633,7 +633,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_alert).performClick();
         mTestableLooper.processAllMessages();
@@ -647,7 +647,7 @@
         int originalImportance = mNotificationChannel.getImportance();
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.handleCloseControls(true, false);
         mTestableLooper.processAllMessages();
@@ -662,7 +662,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.handleCloseControls(true, false);
 
@@ -680,7 +680,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
                 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
                 null /* onSettingsClick */, null /* onAppSettingsClick */ ,
-                true, false /* isNonblockable */, IMPORTANCE_DEFAULT
+                true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
         );
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
@@ -702,7 +702,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
                 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
                 null /* onSettingsClick */, null /* onAppSettingsClick */,
-                true, false /* isNonblockable */, IMPORTANCE_DEFAULT
+                true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
         );
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
@@ -724,7 +724,7 @@
                 null /* onSettingsClick */, null /* onAppSettingsClick */ ,
                 true /* provisioned */,
                 false /* isNonblockable */, true /* isForBlockingHelper */,
-                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT);
+                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
 
         NotificationGuts guts = spy(new NotificationGuts(mContext, null));
         when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -752,7 +752,7 @@
                 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
                 null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */,
                 false /* isNonblockable */, true /* isForBlockingHelper */,
-                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT);
+                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
 
         NotificationGuts guts = spy(new NotificationGuts(mContext, null));
         when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -781,7 +781,7 @@
                 null /* onSettingsClick */, null /* onAppSettingsClick */ ,
                 false /* isNonblockable */, true /* isForBlockingHelper */,
                 true, true /* isUserSentimentNegative */,  /* isNoisy */
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
 
@@ -800,7 +800,7 @@
                 null /* onSettingsClick */, null /* onAppSettingsClick */,
                 true /* provisioned */,
                 false /* isNonblockable */, true /* isForBlockingHelper */,
-                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT);
+                true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.block).performClick();
         mTestableLooper.processAllMessages();
@@ -823,7 +823,7 @@
                 true /* isForBlockingHelper */,
                 true,
                 false /* isUserSentimentNegative */,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
         NotificationGuts guts = mock(NotificationGuts.class);
         doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
         mNotificationInfo.setGutsParent(guts);
@@ -838,7 +838,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
         mNotificationInfo.findViewById(R.id.block).performClick();
         waitForUndoButton();
 
@@ -852,7 +852,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
@@ -888,7 +888,8 @@
                 false /* isNonblockable */,
                 true /* isForBlockingHelper */,
                 true /* isUserSentimentNegative */,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT,
+                false);
 
         mNotificationInfo.findViewById(R.id.block).performClick();
         waitForUndoButton();
@@ -913,7 +914,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
 
@@ -928,7 +929,7 @@
         mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -949,7 +950,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.handleCloseControls(true, false);
 
@@ -967,7 +968,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
@@ -988,7 +989,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -1006,7 +1007,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.int_silent).performClick();
         waitForUndoButton();
@@ -1027,7 +1028,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_alert).performClick();
         waitForUndoButton();
@@ -1049,7 +1050,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.int_silent).performClick();
         waitForUndoButton();
@@ -1071,7 +1072,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_LOW);
+                IMPORTANCE_LOW, false);
 
         mNotificationInfo.findViewById(R.id.int_alert).performClick();
         waitForUndoButton();
@@ -1092,7 +1093,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -1108,7 +1109,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
@@ -1125,7 +1126,7 @@
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
-                }, null, null, true, true, IMPORTANCE_DEFAULT);
+                }, null, null, true, true, IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         mTestableLooper.processAllMessages();
@@ -1143,7 +1144,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                     saveImportance.run();
-                }, null, null, true, false, IMPORTANCE_DEFAULT
+                }, null, null, true, false, IMPORTANCE_DEFAULT, false
         );
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
@@ -1170,7 +1171,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.minimize).performClick();
         waitForUndoButton();
@@ -1183,7 +1184,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
@@ -1196,7 +1197,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, true);
 
         mNotificationInfo.findViewById(R.id.int_silent).performClick();
         waitForUndoButton();
@@ -1210,7 +1211,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_alert).performClick();
         waitForUndoButton();
@@ -1224,7 +1225,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
@@ -1236,7 +1237,7 @@
         mNotificationChannel.setImportance(IMPORTANCE_LOW);
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
-                IMPORTANCE_DEFAULT);
+                IMPORTANCE_DEFAULT, false);
 
         mNotificationInfo.findViewById(R.id.int_block).performClick();
         waitForUndoButton();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 736f384..ae70b01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -352,7 +352,7 @@
                     RETURNS_DEEP_STUBS);
             String key = Integer.toString(i);
             when(row.getStatusBarNotification().getKey()).thenReturn(key);
-            when(mNotificationData.isHighPriority(row.getStatusBarNotification())).thenReturn(true);
+            when(row.getEntry().isHighPriority()).thenReturn(true);
             when(mStackScroller.getChildAt(i)).thenReturn(row);
         }
 
@@ -368,8 +368,7 @@
                     RETURNS_DEEP_STUBS);
             String key = Integer.toString(i);
             when(row.getStatusBarNotification().getKey()).thenReturn(key);
-            when(mNotificationData.isHighPriority(row.getStatusBarNotification()))
-                    .thenReturn(false);
+            when(row.getEntry().isHighPriority()).thenReturn(false);
             when(mStackScroller.getChildAt(i)).thenReturn(row);
         }
 
@@ -385,8 +384,7 @@
                     RETURNS_DEEP_STUBS);
             String key = Integer.toString(i);
             when(row.getStatusBarNotification().getKey()).thenReturn(key);
-            when(mNotificationData.isHighPriority(row.getStatusBarNotification()))
-                    .thenReturn(i < 3);
+            when(row.getEntry().isHighPriority()).thenReturn(i < 3);
             when(mStackScroller.getChildAt(i)).thenReturn(row);
         }
 
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index d1aa84f..73fcb01 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6780,22 +6780,22 @@
     CONVERSATION_ACTIONS = 1615;
 
     // ACTION: Actions from a text classifier are shown to user.
-    // CATEGORY: CONVERSATION_ACTIONS
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
     // OS: Q
     ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN = 1616;
 
-    // ACTION: Event time of a text classifier event in unix timestamp.
-    // CATEGORY: CONVERSATION_ACTIONS, LANGUAGE_DETECTION
+    // FIELD: Event time of a text classifier event in unix timestamp.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
     // OS: Q
     FIELD_TEXT_CLASSIFIER_EVENT_TIME = 1617;
 
     // ACTION: Users compose their own replies instead of using suggested ones.
-    // CATEGORY: CONVERSATION_ACTIONS
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
     // OS: Q
     ACTION_TEXT_CLASSIFIER_MANUAL_REPLY = 1618;
 
     // ACTION: Text classifier generates an action.
-    // CATEGORY: CONVERSATION_ACTIONS
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
     // OS: Q
     ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED = 1619;
 
@@ -6840,7 +6840,7 @@
     // OPEN: Settings > Display > Adaptive sleep
     // OS: Q
     SETTINGS_ADAPTIVE_SLEEP = 1628;
-    
+
     // Tagged data for SMART_REPLY_VISIBLE and NOTIFICATION_ITEM_ACTION.
     // The UI location of the notification containing the smart suggestions.
     // This is a NotificationLocation object (see the NotificationLocation
@@ -6870,6 +6870,40 @@
     // OS: Q
     DIALOG_AWARE_DISABLE = 1633;
 
+    // FIELD: Session ID of TextClassifierEvent.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_SESSION_ID = 1634;
+
+    // FIELD: First entity type.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE = 1635;
+    // FIELD: Second entity type.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE = 1636;
+
+    // FIELD: Third entity type.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE = 1637;
+
+    // FIELD: Score of the suggestion.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_SCORE = 1638;
+
+    // FIELD: widget type, e.g: notification, textview
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_WIDGET_TYPE = 1639;
+
+    // FIELD: version of the widget.
+    // CATEGORY: LANGUAGE_DETECTION, CONVERSATION_ACTIONS
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_WIDGET_VERSION = 1640;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index bcff4e0..303230b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -402,7 +402,7 @@
                 MagnificationGestureHandler magnificationGestureHandler =
                         new MagnificationGestureHandler(mContext,
                                 mAms.getMagnificationController(),
-                                detectControlGestures, triggerable);
+                                detectControlGestures, triggerable, displayId);
                 addFirstEventHandler(displayId, magnificationGestureHandler);
                 mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 49db488..2fbaee6 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -43,7 +43,6 @@
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.TypedValue;
-import android.view.Display;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MotionEvent;
@@ -149,6 +148,8 @@
     private PointerCoords[] mTempPointerCoords;
     private PointerProperties[] mTempPointerProperties;
 
+    private final int mDisplayId;
+
     private final Queue<MotionEvent> mDebugInputEventHistory;
     private final Queue<MotionEvent> mDebugOutputEventHistory;
 
@@ -162,11 +163,13 @@
      * @param detectShortcutTrigger {@code true} if this detector should be "triggerable" by some
      *                           external shortcut invoking {@link #notifyShortcutTriggered},
      *                           {@code false} if it should ignore such triggers.
+     * @param displayId The logical display id.
      */
     public MagnificationGestureHandler(Context context,
             MagnificationController magnificationController,
             boolean detectTripleTap,
-            boolean detectShortcutTrigger) {
+            boolean detectShortcutTrigger,
+            int displayId) {
         if (DEBUG_ALL) {
             Log.i(LOG_TAG,
                     "MagnificationGestureHandler(detectTripleTap = " + detectTripleTap
@@ -174,6 +177,7 @@
         }
 
         mMagnificationController = magnificationController;
+        mDisplayId = displayId;
 
         mDelegatingState = new DelegatingState();
         mDetectingState = new DetectingState(context);
@@ -259,8 +263,7 @@
 
     void notifyShortcutTriggered() {
         if (mDetectShortcutTrigger) {
-            // TODO: multi-display support for magnification gesture handler
-            boolean wasMagnifying = mMagnificationController.resetIfNeeded(Display.DEFAULT_DISPLAY,
+            boolean wasMagnifying = mMagnificationController.resetIfNeeded(mDisplayId,
                     /* animate */ true);
             if (wasMagnifying) {
                 clearAndTransitionToStateDetecting();
@@ -422,8 +425,7 @@
                 Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
                         + " scrollY: " + distanceY);
             }
-            // TODO: multi-display support for magnification gesture handler
-            mMagnificationController.offsetMagnifiedRegion(Display.DEFAULT_DISPLAY, distanceX,
+            mMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX,
                     distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return /* event consumed: */ true;
         }
@@ -440,8 +442,7 @@
                 return mScaling;
             }
 
-            // TODO: multi-display support for magnification gesture handler
-            final float initialScale = mMagnificationController.getScale(Display.DEFAULT_DISPLAY);
+            final float initialScale = mMagnificationController.getScale(mDisplayId);
             final float targetScale = initialScale * detector.getScaleFactor();
 
             // Don't allow a gesture to move the user further outside the
@@ -463,8 +464,7 @@
             final float pivotX = detector.getFocusX();
             final float pivotY = detector.getFocusY();
             if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x");
-            // TODO: multi-display support for magnification gesture handler
-            mMagnificationController.setScale(Display.DEFAULT_DISPLAY, scale, pivotX, pivotY, false,
+            mMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return /* handled: */ true;
         }
@@ -524,10 +524,9 @@
                     }
                     final float eventX = event.getX();
                     final float eventY = event.getY();
-                    // TODO: multi-display support for magnification gesture handler
                     if (mMagnificationController.magnificationRegionContains(
-                            Display.DEFAULT_DISPLAY, eventX, eventY)) {
-                        mMagnificationController.setCenter(Display.DEFAULT_DISPLAY, eventX, eventY,
+                            mDisplayId, eventX, eventY)) {
+                        mMagnificationController.setCenter(mDisplayId, eventX, eventY,
                                 /* animate */ mLastMoveOutsideMagnifiedRegion,
                                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
                         mLastMoveOutsideMagnifiedRegion = false;
@@ -665,9 +664,8 @@
 
                     mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
 
-                    // TODO: multi-display support for magnification gesture handler
                     if (!mMagnificationController.magnificationRegionContains(
-                            Display.DEFAULT_DISPLAY, event.getX(), event.getY())) {
+                            mDisplayId, event.getX(), event.getY())) {
 
                         transitionToDelegatingStateAndClear();
 
@@ -684,8 +682,7 @@
                             // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
                             // to ensure reachability of
                             // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
-                            // TODO: multi-display support for magnification gesture handler
-                            || mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
+                            || mMagnificationController.isMagnifying(mDisplayId)) {
 
                         afterMultiTapTimeoutTransitionToDelegatingState();
 
@@ -697,8 +694,7 @@
                 }
                 break;
                 case ACTION_POINTER_DOWN: {
-                    // TODO: multi-display support for magnification gesture handler
-                    if (mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
+                    if (mMagnificationController.isMagnifying(mDisplayId)) {
                         transitionTo(mPanningScalingState);
                         clear();
                     } else {
@@ -727,9 +723,8 @@
 
                     mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
 
-                    // TODO: multi-display support for magnification gesture handler
                     if (!mMagnificationController.magnificationRegionContains(
-                            Display.DEFAULT_DISPLAY, event.getX(), event.getY())) {
+                            mDisplayId, event.getX(), event.getY())) {
 
                         transitionToDelegatingStateAndClear();
 
@@ -880,8 +875,7 @@
             clear();
 
             // Toggle zoom
-            // TODO: multi-display support for magnification gesture handler
-            if (mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
+            if (mMagnificationController.isMagnifying(mDisplayId)) {
                 zoomOff();
             } else {
                 zoomOn(up.getX(), up.getY());
@@ -893,9 +887,8 @@
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
             clear();
 
-            // TODO: multi-display support for magnification gesture handler
             mViewportDraggingState.mZoomedInBeforeDrag =
-                    mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY);
+                    mMagnificationController.isMagnifying(mDisplayId);
 
             zoomOn(down.getX(), down.getY());
 
@@ -922,8 +915,7 @@
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "setShortcutTriggered(" + state + ")");
 
             mShortcutTriggered = state;
-            // TODO: multi-display support for magnification gesture handler
-            mMagnificationController.setForceShowMagnifiableBounds(Display.DEFAULT_DISPLAY, state);
+            mMagnificationController.setForceShowMagnifiableBounds(mDisplayId, state);
         }
 
         /**
@@ -958,8 +950,7 @@
         final float scale = MathUtils.constrain(
                 mMagnificationController.getPersistedScale(),
                 MIN_SCALE, MAX_SCALE);
-        // TODO: multi-display support for magnification gesture handler
-        mMagnificationController.setScaleAndCenter(Display.DEFAULT_DISPLAY,
+        mMagnificationController.setScaleAndCenter(mDisplayId,
                 scale, centerX, centerY,
                 /* animate */ true,
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
@@ -967,8 +958,7 @@
 
     private void zoomOff() {
         if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()");
-        // TODO: multi-display support for magnification gesture handler
-        mMagnificationController.reset(Display.DEFAULT_DISPLAY, /* animate */ true);
+        mMagnificationController.reset(mDisplayId, /* animate */ true);
     }
 
     private static MotionEvent recycleAndNullify(@Nullable MotionEvent event) {
@@ -990,6 +980,7 @@
                 ", mCurrentState=" + State.nameOf(mCurrentState) +
                 ", mPreviousState=" + State.nameOf(mPreviousState) +
                 ", mMagnificationController=" + mMagnificationController +
+                ", mDisplayId=" + mDisplayId +
                 '}';
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 8ffadde..65e31f3 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -435,7 +435,7 @@
         MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
                 event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
                 coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
-                event.getSource(), event.getFlags());
+                event.getSource(), event.getDisplayId(), event.getFlags());
         final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
         sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
         click_event.recycle();
@@ -1029,7 +1029,7 @@
                 event.getEventTime(), event.getAction(), event.getPointerCount(),
                 props, coords, event.getMetaState(), event.getButtonState(),
                 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
-                event.getSource(), event.getFlags());
+                event.getSource(), event.getDisplayId(), event.getFlags());
     }
 
     /**
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 4f58d79..303734a 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.backup.BackupManagerService.TAG;
 
+import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManager;
@@ -41,9 +42,10 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.Settings;
+import android.os.UserManager;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
 
 import java.io.File;
@@ -75,19 +77,25 @@
  * system user is unlocked before any other users.
  */
 public class Trampoline extends IBackupManager.Stub {
-    // When this file is present, the backup service is inactive.
+    /**
+     * Name of file that disables the backup service. If this file exists, then backup is disabled
+     * for all users.
+     */
     private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
 
+    /**
+     * Name of file for non-system users that enables the backup service for the user. Backup is
+     * disabled by default in non-system users.
+     */
+    private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
+
     // Product-level suppression of backup/restore.
     private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
 
     private static final String BACKUP_THREAD = "backup";
 
-    /** Values for setting {@link Settings.Global#BACKUP_MULTI_USER_ENABLED} */
-    private static final int MULTI_USER_DISABLED = 0;
-    private static final int MULTI_USER_ENABLED = 1;
-
     private final Context mContext;
+    private final UserManager mUserManager;
 
     private final boolean mGlobalDisable;
     // Lock to write backup suppress files.
@@ -104,20 +112,13 @@
         mHandlerThread = new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
+        mUserManager = UserManager.get(context);
     }
 
     protected boolean isBackupDisabled() {
         return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
     }
 
-    private boolean isMultiUserEnabled() {
-        return Settings.Global.getInt(
-                mContext.getContentResolver(),
-                Settings.Global.BACKUP_MULTI_USER_ENABLED,
-                MULTI_USER_DISABLED)
-                == MULTI_USER_ENABLED;
-    }
-
     protected int binderGetCallingUserId() {
         return Binder.getCallingUserHandle().getIdentifier();
     }
@@ -126,21 +127,65 @@
         return Binder.getCallingUid();
     }
 
-    protected File getSuppressFileForUser(int userId) {
-        return new File(UserBackupManagerFiles.getBaseStateDir(userId),
+    /** Stored in the system user's directory. */
+    protected File getSuppressFileForSystemUser() {
+        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
                 BACKUP_SUPPRESS_FILENAME);
     }
 
-    protected void createBackupSuppressFileForUser(int userId) throws IOException {
-        synchronized (mStateLock) {
-            getSuppressFileForUser(userId).getParentFile().mkdirs();
-            getSuppressFileForUser(userId).createNewFile();
+    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+    protected File getActivatedFileForNonSystemUser(int userId) {
+        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
+                BACKUP_ACTIVATED_FILENAME + "-" + userId);
+    }
+
+    private void createFile(File file) throws IOException {
+        if (file.exists()) {
+            return;
+        }
+
+        file.getParentFile().mkdirs();
+        if (!file.createNewFile()) {
+            Slog.w(TAG, "Failed to create file " + file.getPath());
         }
     }
 
-    private void deleteBackupSuppressFileForUser(int userId) {
-        if (!getSuppressFileForUser(userId).delete()) {
-            Slog.w(TAG, "Failed deleting backup suppressed file for user: " + userId);
+    private void deleteFile(File file) {
+        if (!file.exists()) {
+            return;
+        }
+
+        if (!file.delete()) {
+            Slog.w(TAG, "Failed to delete file " + file.getPath());
+        }
+    }
+
+    /**
+     * Deactivates the backup service for user {@code userId}. If this is the system user, it
+     * creates a suppress file which disables backup for all users. If this is a non-system user, it
+     * only deactivates backup for that user by deleting its activate file.
+     */
+    @GuardedBy("mStateLock")
+    private void deactivateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            createFile(getSuppressFileForSystemUser());
+        } else {
+            deleteFile(getActivatedFileForNonSystemUser(userId));
+        }
+    }
+
+    /**
+     * Enables the backup service for user {@code userId}. If this is the system user, it deletes
+     * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
+     * deleting the suppress file does not automatically enable backup for non-system users, they
+     * need their own activate file in order to participate in the service.
+     */
+    @GuardedBy("mStateLock")
+    private void activateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            deleteFile(getSuppressFileForSystemUser());
+        } else {
+            createFile(getActivatedFileForNonSystemUser(userId));
         }
     }
 
@@ -148,24 +193,31 @@
     // admin (device owner or profile owner).
     private boolean isUserReadyForBackup(int userId) {
         return mService != null && mService.getServiceUsers().get(userId) != null
-                && !isBackupSuppressedForUser(userId);
+                && isBackupActivatedForUser(userId);
     }
 
-    private boolean isBackupSuppressedForUser(int userId) {
-        // If backup is disabled for system user, it's disabled for all other users on device.
-        if (getSuppressFileForUser(UserHandle.USER_SYSTEM).exists()) {
-            return true;
+    /**
+     * Backup is activated for the system user if the suppress file does not exist. Backup is
+     * activated for non-system users if the suppress file does not exist AND the user's activated
+     * file exists.
+     */
+    private boolean isBackupActivatedForUser(int userId) {
+        if (getSuppressFileForSystemUser().exists()) {
+            return false;
         }
-        if (userId != UserHandle.USER_SYSTEM) {
-            return getSuppressFileForUser(userId).exists();
-        }
-        return false;
+
+        return userId == UserHandle.USER_SYSTEM
+                || getActivatedFileForNonSystemUser(userId).exists();
     }
 
     protected Context getContext() {
         return mContext;
     }
 
+    protected UserManager getUserManager() {
+        return mUserManager;
+    }
+
     protected BackupManagerService createBackupManagerService() {
         return new BackupManagerService(mContext, this, mHandlerThread);
     }
@@ -198,23 +250,17 @@
 
     /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
-     * Starts the backup service for this user if it's the system user or if the service supports
-     * multi-user. Offloads work onto the handler thread {@link #mHandlerThread} to keep unlock time
-     * low.
+     * Starts the backup service for this user if backup is active for this user. Offloads work onto
+     * the handler thread {@link #mHandlerThread} to keep unlock time low.
      */
     void unlockUser(int userId) {
-        if (userId != UserHandle.USER_SYSTEM && !isMultiUserEnabled()) {
-            Slog.i(TAG, "Multi-user disabled, cannot start service for user: " + userId);
-            return;
-        }
-
         postToHandler(() -> startServiceForUser(userId));
     }
 
     private void startServiceForUser(int userId) {
         // We know that the user is unlocked here because it is called from setBackupServiceActive
         // and unlockUser which have these guarantees. So we can check if the file exists.
-        if (mService != null && !isBackupSuppressedForUser(userId)) {
+        if (mService != null && isBackupActivatedForUser(userId)) {
             Slog.i(TAG, "Starting service for user: " + userId);
             mService.startServiceForUser(userId);
         }
@@ -225,11 +271,6 @@
      * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
      */
     void stopUser(int userId) {
-        if (userId != UserHandle.USER_SYSTEM && !isMultiUserEnabled()) {
-            Slog.i(TAG, "Multi-user disabled, cannot stop service for user: " + userId);
-            return;
-        }
-
         postToHandler(
                 () -> {
                     if (mService != null) {
@@ -240,45 +281,63 @@
     }
 
     /**
-     * Only privileged callers should be changing the backup state. This method only acts on {@link
-     * UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the
-     * system user also deactivates backup in all users.
-     *
-     * This call will only work if the calling {@code userID} is unlocked.
+     * The system user and managed profiles can only be acted on by callers in the system or root
+     * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
+     * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
+     */
+    private void enforcePermissionsOnUser(int userId) throws SecurityException {
+        boolean isRestrictedUser =
+                userId == UserHandle.USER_SYSTEM
+                        || getUserManager().getUserInfo(userId).isManagedProfile();
+
+        if (isRestrictedUser) {
+            int caller = binderGetCallingUid();
+            if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
+                throw new SecurityException("No permission to configure backup activity");
+            }
+        } else {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.BACKUP, "No permission to configure backup activity");
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "No permission to configure backup activity");
+        }
+    }
+
+    /**
+     * Only privileged callers should be changing the backup state. Deactivating backup in the
+     * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
+     * is unlocked at this point yet, so handle both cases.
      */
     public void setBackupServiceActive(int userId, boolean makeActive) {
-        int caller = binderGetCallingUid();
-        if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
-            throw new SecurityException("No permission to configure backup activity");
-        }
+        enforcePermissionsOnUser(userId);
 
         if (mGlobalDisable) {
             Slog.i(TAG, "Backup service not supported");
             return;
         }
 
-        if (userId != UserHandle.USER_SYSTEM) {
-            Slog.i(TAG, "Cannot set backup service activity for non-system user: " + userId);
-            return;
-        }
-
-        if (makeActive == isBackupServiceActive(userId)) {
-            Slog.i(TAG, "No change in backup service activity");
-            return;
-        }
-
         synchronized (mStateLock) {
             Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
             if (makeActive) {
                 if (mService == null) {
                     mService = createBackupManagerService();
                 }
-                deleteBackupSuppressFileForUser(userId);
-                startServiceForUser(userId);
+                try {
+                    activateBackupForUserLocked(userId);
+                } catch (IOException e) {
+                    Slog.e(TAG, "Unable to persist backup service activity");
+                }
+
+                // If the user is unlocked, we can start the backup service for it. Otherwise we
+                // will start the service when the user is unlocked as part of its unlock callback.
+                if (getUserManager().isUserUnlocked(userId)) {
+                    startServiceForUser(userId);
+                }
             } else {
                 try {
                     //TODO(b/121198006): what if this throws an exception?
-                    createBackupSuppressFileForUser(userId);
+                    deactivateBackupForUserLocked(userId);
                 } catch (IOException e) {
                     Slog.e(TAG, "Unable to persist backup service inactivity");
                 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1519c17..14e2354 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1884,12 +1884,6 @@
                 "ConnectivityService");
     }
 
-    private void enforceControlAlwaysOnVpnPermission() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
-                "ConnectivityService");
-    }
-
     private void enforceNetworkStackSettingsOrSetup() {
         enforceAnyPermissionOf(
             android.Manifest.permission.NETWORK_SETTINGS,
@@ -1897,12 +1891,6 @@
             android.Manifest.permission.NETWORK_STACK);
     }
 
-    private void enforceNetworkStackPermission() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.NETWORK_STACK,
-                "ConnectivityService");
-    }
-
     private boolean checkNetworkStackPermission() {
         return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.NETWORK_STACK);
@@ -4159,9 +4147,8 @@
     }
 
     @Override
-    public boolean setAlwaysOnVpnPackage(
-            int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) {
-        enforceControlAlwaysOnVpnPermission();
+    public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) {
+        enforceConnectivityInternalPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4175,11 +4162,11 @@
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
             }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) {
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown)) {
                 return false;
             }
             if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false, null);
+                vpn.setAlwaysOnPackage(null, false);
                 return false;
             }
         }
@@ -4188,7 +4175,7 @@
 
     @Override
     public String getAlwaysOnVpnPackage(int userId) {
-        enforceControlAlwaysOnVpnPermission();
+        enforceConnectivityInternalPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4202,36 +4189,6 @@
     }
 
     @Override
-    public boolean isVpnLockdownEnabled(int userId) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
-                return false;
-            }
-            return vpn.getLockdown();
-        }
-    }
-
-    @Override
-    public List<String> getVpnLockdownWhitelist(int userId) {
-        enforceControlAlwaysOnVpnPermission();
-        enforceCrossUserPermission(userId);
-
-        synchronized (mVpns) {
-            Vpn vpn = mVpns.get(userId);
-            if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
-                return null;
-            }
-            return vpn.getLockdownWhitelist();
-        }
-    }
-
-    @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
         return -1;
@@ -4460,7 +4417,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
                 Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.setAlwaysOnPackage(null, false, null);
+                vpn.setAlwaysOnPackage(null, false);
             }
         }
     }
@@ -6340,7 +6297,7 @@
             synchronized (mVpns) {
                 final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
                 if (alwaysOnPackage != null) {
-                    setAlwaysOnVpnPackage(userId, null, false, null);
+                    setAlwaysOnVpnPackage(userId, null, false);
                     setVpnPackageAuthorization(alwaysOnPackage, userId, false);
                 }
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 89ff338..c064453 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -46,9 +46,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.InetAddresses;
 import android.net.INetd;
-import android.net.INetdUnsolicitedEventListener;
 import android.net.INetworkManagementEventObserver;
 import android.net.ITetheringStatsProvider;
 import android.net.InterfaceConfiguration;
@@ -63,6 +61,7 @@
 import android.net.TetherStatsParcel;
 import android.net.UidRange;
 import android.net.shared.NetdService;
+import android.net.shared.NetworkObserverRegistry;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
@@ -207,16 +206,13 @@
 
     private INetd mNetdService;
 
-    private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener;
+    private NMSNetworkObserverRegistry mNetworkObserverRegistry;
 
     private IBatteryStats mBatteryStats;
 
     private final Thread mThread;
     private CountDownLatch mConnectedSignal = new CountDownLatch(1);
 
-    private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
-            new RemoteCallbackList<>();
-
     private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
 
     @GuardedBy("mTetheringStatsProviders")
@@ -326,8 +322,6 @@
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
-        mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
-
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
@@ -346,7 +340,7 @@
         mFgHandler = null;
         mThread = null;
         mServices = null;
-        mNetdUnsolicitedEventListener = null;
+        mNetworkObserverRegistry = null;
     }
 
     static NetworkManagementService create(Context context, String socket, SystemServices services)
@@ -394,14 +388,12 @@
 
     @Override
     public void registerObserver(INetworkManagementEventObserver observer) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        mObservers.register(observer);
+        mNetworkObserverRegistry.registerObserver(observer);
     }
 
     @Override
     public void unregisterObserver(INetworkManagementEventObserver observer) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        mObservers.unregister(observer);
+        mNetworkObserverRegistry.unregisterObserver(observer);
     }
 
     @FunctionalInterface
@@ -409,127 +401,101 @@
         public void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
     }
 
-    private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    eventCallback.sendCallback(mObservers.getBroadcastItem(i));
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
+    private class NMSNetworkObserverRegistry extends NetworkObserverRegistry {
+        NMSNetworkObserverRegistry(Context context, Handler handler, INetd netd)
+                throws RemoteException {
+            super(context, handler, netd);
         }
-    }
 
-    /**
-     * Notify our observers of an interface status change
-     */
-    private void notifyInterfaceStatusChanged(String iface, boolean up) {
-        invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up));
-    }
+        /**
+         * Notify our observers of a change in the data activity state of the interface
+         */
+        @Override
+        public void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
+                int uid, boolean fromRadio) {
+            final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
+            int powerState = isActive
+                    ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                    : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
 
-    /**
-     * Notify our observers of an interface link state change
-     * (typically, an Ethernet cable has been plugged-in or unplugged).
-     */
-    private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
-        invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up));
-    }
-
-    /**
-     * Notify our observers of an interface addition.
-     */
-    private void notifyInterfaceAdded(String iface) {
-        invokeForAllObservers(o -> o.interfaceAdded(iface));
-    }
-
-    /**
-     * Notify our observers of an interface removal.
-     */
-    private void notifyInterfaceRemoved(String iface) {
-        // netd already clears out quota and alerts for removed ifaces; update
-        // our sanity-checking state.
-        mActiveAlerts.remove(iface);
-        mActiveQuotas.remove(iface);
-        invokeForAllObservers(o -> o.interfaceRemoved(iface));
-    }
-
-    /**
-     * Notify our observers of a limit reached.
-     */
-    private void notifyLimitReached(String limitName, String iface) {
-        invokeForAllObservers(o -> o.limitReached(limitName, iface));
-    }
-
-    /**
-     * Notify our observers of a change in the data activity state of the interface
-     */
-    private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
-            int uid, boolean fromRadio) {
-        final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
-        if (isMobile) {
-            if (!fromRadio) {
-                if (mMobileActivityFromRadio) {
-                    // If this call is not coming from a report from the radio itself, but we
-                    // have previously received reports from the radio, then we will take the
-                    // power state to just be whatever the radio last reported.
-                    powerState = mLastPowerStateFromRadio;
+            if (isMobile) {
+                if (!fromRadio) {
+                    if (mMobileActivityFromRadio) {
+                        // If this call is not coming from a report from the radio itself, but we
+                        // have previously received reports from the radio, then we will take the
+                        // power state to just be whatever the radio last reported.
+                        powerState = mLastPowerStateFromRadio;
+                    }
+                } else {
+                    mMobileActivityFromRadio = true;
                 }
-            } else {
-                mMobileActivityFromRadio = true;
-            }
-            if (mLastPowerStateFromRadio != powerState) {
-                mLastPowerStateFromRadio = powerState;
-                try {
-                    getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
+                if (mLastPowerStateFromRadio != powerState) {
+                    mLastPowerStateFromRadio = powerState;
+                    try {
+                        getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
+                    } catch (RemoteException e) {
+                    }
                 }
                 StatsLog.write_non_chained(StatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, null,
                         powerState);
             }
-        }
 
-        if (ConnectivityManager.isNetworkTypeWifi(type)) {
-            if (mLastPowerStateFromWifi != powerState) {
-                mLastPowerStateFromWifi = powerState;
-                try {
-                    getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
+            if (ConnectivityManager.isNetworkTypeWifi(type)) {
+                if (mLastPowerStateFromWifi != powerState) {
+                    mLastPowerStateFromWifi = powerState;
+                    try {
+                        getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
+                    } catch (RemoteException e) {
+                    }
                 }
                 StatsLog.write_non_chained(StatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, null,
                         powerState);
             }
-        }
 
-        boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
-                || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
-
-        if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
-            // Report the change in data activity.  We don't do this if this is a change
-            // on the mobile network, that is not coming from the radio itself, and we
-            // have previously seen change reports from the radio.  In that case only
-            // the radio is the authority for the current state.
-            final boolean active = isActive;
-            invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
-                    Integer.toString(type), active, tsNanos));
-        }
-
-        boolean report = false;
-        synchronized (mIdleTimerLock) {
-            if (mActiveIdleTimers.isEmpty()) {
-                // If there are no idle timers, we are not monitoring activity, so we
-                // are always considered active.
-                isActive = true;
+            if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
+                // Report the change in data activity.  We don't do this if this is a change
+                // on the mobile network, that is not coming from the radio itself, and we
+                // have previously seen change reports from the radio.  In that case only
+                // the radio is the authority for the current state.
+                final boolean active = isActive;
+                super.notifyInterfaceClassActivity(type, isActive, tsNanos, uid, fromRadio);
             }
-            if (mNetworkActive != isActive) {
-                mNetworkActive = isActive;
-                report = isActive;
+
+            boolean report = false;
+            synchronized (mIdleTimerLock) {
+                if (mActiveIdleTimers.isEmpty()) {
+                    // If there are no idle timers, we are not monitoring activity, so we
+                    // are always considered active.
+                    isActive = true;
+                }
+                if (mNetworkActive != isActive) {
+                    mNetworkActive = isActive;
+                    report = isActive;
+                }
+            }
+            if (report) {
+                reportNetworkActive();
             }
         }
-        if (report) {
-            reportNetworkActive();
+
+        /**
+         * Notify our observers of an interface removal.
+         */
+        @Override
+        public void notifyInterfaceRemoved(String iface) {
+            // netd already clears out quota and alerts for removed ifaces; update
+            // our sanity-checking state.
+            mActiveAlerts.remove(iface);
+            mActiveQuotas.remove(iface);
+            super.notifyInterfaceRemoved(iface);
+        }
+
+        @Override
+        public void onStrictCleartextDetected(int uid, String hex) throws RemoteException {
+            // Don't need to post to mDaemonHandler because the only thing
+            // that notifyCleartextNetwork does is post to a handler
+            ActivityManager.getService().notifyCleartextNetwork(uid,
+                    HexDump.hexStringToByteArray(hex));
         }
     }
 
@@ -558,7 +524,8 @@
                 return;
             }
             // No current code examines the interface parameter in a global alert. Just pass null.
-            mDaemonHandler.post(() -> notifyLimitReached(LIMIT_GLOBAL_ALERT, null));
+            mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyLimitReached(
+                    LIMIT_GLOBAL_ALERT, null));
         }
     }
 
@@ -590,10 +557,11 @@
     private void connectNativeNetdService() {
         mNetdService = mServices.getNetd();
         try {
-            mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
-            if (DBG) Slog.d(TAG, "Register unsolicited event listener");
+            mNetworkObserverRegistry = new NMSNetworkObserverRegistry(
+                    mContext, mDaemonHandler, mNetdService);
+            if (DBG) Slog.d(TAG, "Registered NetworkObserverRegistry");
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Failed to set Netd unsolicited event listener " + e);
+            Slog.wtf(TAG, "Failed to register NetworkObserverRegistry: " + e);
         }
     }
 
@@ -697,120 +665,6 @@
 
     }
 
-    /**
-     * Notify our observers of a new or updated interface address.
-     */
-    private void notifyAddressUpdated(String iface, LinkAddress address) {
-        invokeForAllObservers(o -> o.addressUpdated(iface, address));
-    }
-
-    /**
-     * Notify our observers of a deleted interface address.
-     */
-    private void notifyAddressRemoved(String iface, LinkAddress address) {
-        invokeForAllObservers(o -> o.addressRemoved(iface, address));
-    }
-
-    /**
-     * Notify our observers of DNS server information received.
-     */
-    private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
-        invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses));
-    }
-
-    /**
-     * Notify our observers of a route change.
-     */
-    private void notifyRouteChange(boolean updated, RouteInfo route) {
-        if (updated) {
-            invokeForAllObservers(o -> o.routeUpdated(route));
-        } else {
-            invokeForAllObservers(o -> o.routeRemoved(route));
-        }
-    }
-
-    private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
-        @Override
-        public void onInterfaceClassActivityChanged(boolean isActive,
-                int label, long timestamp, int uid) throws RemoteException {
-            final long timestampNanos;
-            if (timestamp <= 0) {
-                timestampNanos = SystemClock.elapsedRealtimeNanos();
-            } else {
-                timestampNanos = timestamp;
-            }
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(label,
-                    isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
-                    : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
-                    timestampNanos, uid, false));
-        }
-
-        @Override
-        public void onQuotaLimitReached(String alertName, String ifName)
-                throws RemoteException {
-            mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName));
-        }
-
-        @Override
-        public void onInterfaceDnsServerInfo(String ifName,
-                long lifetime, String[] servers) throws RemoteException {
-            mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers));
-        }
-
-        @Override
-        public void onInterfaceAddressUpdated(String addr,
-                String ifName, int flags, int scope) throws RemoteException {
-            final LinkAddress address = new LinkAddress(addr, flags, scope);
-            mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address));
-        }
-
-        @Override
-        public void onInterfaceAddressRemoved(String addr,
-                String ifName, int flags, int scope) throws RemoteException {
-            final LinkAddress address = new LinkAddress(addr, flags, scope);
-            mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address));
-        }
-
-        @Override
-        public void onInterfaceAdded(String ifName) throws RemoteException {
-            mDaemonHandler.post(() -> notifyInterfaceAdded(ifName));
-        }
-
-        @Override
-        public void onInterfaceRemoved(String ifName) throws RemoteException {
-            mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName));
-        }
-
-        @Override
-        public void onInterfaceChanged(String ifName, boolean up)
-                throws RemoteException {
-            mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up));
-        }
-
-        @Override
-        public void onInterfaceLinkStateChanged(String ifName, boolean up)
-                throws RemoteException {
-            mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up));
-        }
-
-        @Override
-        public void onRouteChanged(boolean updated,
-                String route, String gateway, String ifName) throws RemoteException {
-            final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
-                    ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
-                    ifName);
-            mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
-        }
-
-        @Override
-        public void onStrictCleartextDetected(int uid, String hex) throws RemoteException {
-            // Don't need to post to mDaemonHandler because the only thing
-            // that notifyCleartextNetwork does is post to a handler
-            ActivityManager.getService().notifyCleartextNetwork(uid,
-                    HexDump.hexStringToByteArray(hex));
-        }
-    }
-
     //
     // Netd Callback handling
     //
@@ -859,16 +713,18 @@
                         throw new IllegalStateException(errorMessage);
                     }
                     if (cooked[2].equals("added")) {
-                        notifyInterfaceAdded(cooked[3]);
+                        mNetworkObserverRegistry.notifyInterfaceAdded(cooked[3]);
                         return true;
                     } else if (cooked[2].equals("removed")) {
-                        notifyInterfaceRemoved(cooked[3]);
+                        mNetworkObserverRegistry.notifyInterfaceRemoved(cooked[3]);
                         return true;
                     } else if (cooked[2].equals("changed") && cooked.length == 5) {
-                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
+                        mNetworkObserverRegistry.notifyInterfaceStatusChanged(
+                                cooked[3], cooked[4].equals("up"));
                         return true;
                     } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
-                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
+                        mNetworkObserverRegistry.notifyInterfaceLinkStateChanged(
+                                cooked[3], cooked[4].equals("up"));
                         return true;
                     }
                     throw new IllegalStateException(errorMessage);
@@ -882,7 +738,7 @@
                         throw new IllegalStateException(errorMessage);
                     }
                     if (cooked[2].equals("alert")) {
-                        notifyLimitReached(cooked[3], cooked[4]);
+                        mNetworkObserverRegistry.notifyLimitReached(cooked[3], cooked[4]);
                         return true;
                     }
                     throw new IllegalStateException(errorMessage);
@@ -908,9 +764,8 @@
                         timestampNanos = SystemClock.elapsedRealtimeNanos();
                     }
                     boolean isActive = cooked[2].equals("active");
-                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
-                            isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
-                            : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+                    mNetworkObserverRegistry.notifyInterfaceClassActivity(
+                            Integer.parseInt(cooked[3]), isActive,
                             timestampNanos, processUid, false);
                     return true;
                     // break;
@@ -937,9 +792,9 @@
                     }
 
                     if (cooked[2].equals("updated")) {
-                        notifyAddressUpdated(iface, address);
+                        mNetworkObserverRegistry.notifyAddressUpdated(iface, address);
                     } else {
-                        notifyAddressRemoved(iface, address);
+                        mNetworkObserverRegistry.notifyAddressRemoved(iface, address);
                     }
                     return true;
                     // break;
@@ -959,7 +814,8 @@
                             throw new IllegalStateException(errorMessage);
                         }
                         String[] servers = cooked[5].split(",");
-                        notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
+                        mNetworkObserverRegistry.notifyInterfaceDnsServerInfo(
+                                cooked[3], lifetime, servers);
                     }
                     return true;
                     // break;
@@ -998,7 +854,8 @@
                             InetAddress gateway = null;
                             if (via != null) gateway = InetAddress.parseNumericAddress(via);
                             RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
-                            notifyRouteChange(cooked[2].equals("updated"), route);
+                            mNetworkObserverRegistry.notifyRouteChange(
+                                    cooked[2].equals("updated"), route);
                             return true;
                         } catch (IllegalArgumentException e) {}
                     }
@@ -1461,9 +1318,8 @@
             if (ConnectivityManager.isNetworkTypeMobile(type)) {
                 mNetworkActive = false;
             }
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(type,
-                    DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
-                    SystemClock.elapsedRealtimeNanos(), -1, false));
+            mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyInterfaceClassActivity(
+                    type, true /* isActive */, SystemClock.elapsedRealtimeNanos(), -1, false));
         }
     }
 
@@ -1486,9 +1342,9 @@
                 throw new IllegalStateException(e);
             }
             mActiveIdleTimers.remove(iface);
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type,
-                    DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
-                    SystemClock.elapsedRealtimeNanos(), -1, false));
+            mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyInterfaceClassActivity(
+                    params.type, false /* isActive */, SystemClock.elapsedRealtimeNanos(), -1,
+                    false));
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9d810cd..cec825f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -112,6 +112,7 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.sysprop.VoldProperties;
@@ -463,6 +464,7 @@
         = { "password", "default", "pattern", "pin" };
 
     private final Context mContext;
+    private final ContentResolver mResolver;
 
     private volatile IVold mVold;
     private volatile IStoraged mStoraged;
@@ -797,6 +799,14 @@
                     refreshIsolatedStorageSettings();
                 }
             });
+        // For now, simply clone property when it changes
+        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE,
+                mContext.getMainExecutor(), (namespace, name, value) -> {
+                    if (DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED.equals(name)) {
+                        Settings.Global.putString(mResolver,
+                                Settings.Global.ISOLATED_STORAGE_REMOTE, value);
+                    }
+                });
         refreshIsolatedStorageSettings();
     }
 
@@ -1523,6 +1533,8 @@
                 SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)));
 
         mContext = context;
+        mResolver = mContext.getContentResolver();
+
         mCallbacks = new Callbacks(FgThread.get().getLooper());
         mLockPatternUtils = new LockPatternUtils(mContext);
 
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index aabb587..dc9a4bf 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,8 +16,6 @@
 
 package com.android.server.am;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
 import android.content.Context;
 import android.os.Handler;
@@ -26,6 +24,8 @@
 import android.view.WindowManager;
 import android.widget.Button;
 
+import com.android.internal.R;
+
 public class BaseErrorDialog extends AlertDialog {
     private static final int ENABLE_BUTTONS = 0;
     private static final int DISABLE_BUTTONS = 1;
@@ -36,7 +36,7 @@
         super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError);
         context.assertRuntimeOverlayThemable();
 
-        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index d3953b5..3d69aa8 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -61,6 +61,8 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
+        sGlobalSettingToTypeMap.put(
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 55cca95..0b27a8a 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -379,6 +379,10 @@
             if (userId == UserHandle.USER_CURRENT) {
                 userId = controller.mUserController.getCurrentOrTargetUserId();
             }
+            // temporarily allow receivers and services to open activities from background if the
+            // PendingIntent.send() caller was foreground at the time of sendInner() call
+            final boolean allowTrampoline = uid != callingUid
+                    && controller.mAtmInternal.isUidForeground(callingUid);
 
             switch (key.type) {
                 case ActivityManager.INTENT_SENDER_ACTIVITY:
@@ -419,7 +423,8 @@
                                 uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
                                 requiredPermission, options, (finishedReceiver != null),
                                 false, userId,
-                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
+                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
+                                || allowTrampoline);
                         if (sent == ActivityManager.BROADCAST_SUCCESS) {
                             sendFinish = false;
                         }
@@ -433,7 +438,8 @@
                         controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
                                 key.packageName, userId,
-                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
+                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken)
+                                || allowTrampoline);
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startService intent", e);
                     } catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2508844..62a1b03 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -151,7 +151,7 @@
                 .divide(BigInteger.valueOf(100));
     }
     // How many routes to evaluate before bailing and declaring this Vpn should provide
-    // the INTERNET capability. This is necessary because computing the address space is
+    // the INTERNET capability. This is necessary because computing the adress space is
     // O(n²) and this is running in the system service, so a limit is needed to alleviate
     // the risk of attack.
     // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
@@ -194,12 +194,6 @@
     private boolean mLockdown = false;
 
     /**
-     * Set of packages in addition to the VPN app itself that can access the network directly when
-     * VPN is not connected even if {@code mLockdown} is set.
-     */
-    private @NonNull List<String> mLockdownWhitelist = Collections.emptyList();
-
-    /**
      * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
      * when VPN is not running. For example, during system startup or after a crash.
      * @see mLockdown
@@ -326,9 +320,9 @@
      *
      * Used to enable/disable legacy VPN lockdown.
      *
-     * This uses the same ip rule mechanism as
-     * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
-     * that function will be replaced and saved with the always-on state.
+     * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
+     * previous settings from calling that function will be replaced and saved with the
+     * always-on state.
      *
      * @param lockdown whether to prevent all traffic outside of a VPN.
      */
@@ -425,14 +419,12 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
-     * @param lockdownWhitelist packages to be whitelisted from lockdown.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
-    public synchronized boolean setAlwaysOnPackage(
-            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
+    public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
         enforceControlPermissionOrInternalCaller();
 
-        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) {
+        if (setAlwaysOnPackageInternal(packageName, lockdown)) {
             saveAlwaysOnPackage();
             return true;
         }
@@ -447,27 +439,15 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
-     * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if
-     *        {@code lockdown} is {@code true}. Packages must not contain commas.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     @GuardedBy("this")
-    private boolean setAlwaysOnPackageInternal(
-            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
+    private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
         }
 
-        if (lockdownWhitelist != null) {
-            for (String pkg : lockdownWhitelist) {
-                if (pkg.contains(",")) {
-                    Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg);
-                    return false;
-                }
-            }
-        }
-
         if (packageName != null) {
             // Pre-authorize new always-on VPN package.
             if (!setPackageAuthorization(packageName, true)) {
@@ -480,18 +460,13 @@
         }
 
         mLockdown = (mAlwaysOn && lockdown);
-        mLockdownWhitelist = (mLockdown && lockdownWhitelist != null)
-                ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist))
-                : Collections.emptyList();
-
         if (isCurrentPreparedPackage(packageName)) {
             updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
-            setVpnForcedLocked(mLockdown);
         } else {
             // Prepare this app. The notification will update as a side-effect of updateState().
-            // It also calls setVpnForcedLocked().
             prepareInternal(packageName);
         }
+        setVpnForcedLocked(mLockdown);
         return true;
     }
 
@@ -503,6 +478,7 @@
      * @return the package name of the VPN controller responsible for always-on VPN,
      *         or {@code null} if none is set or always-on VPN is controlled through
      *         lockdown instead.
+     * @hide
      */
     public synchronized String getAlwaysOnPackage() {
         enforceControlPermissionOrInternalCaller();
@@ -510,13 +486,6 @@
     }
 
     /**
-     * @return an immutable list of packages whitelisted from always-on VPN lockdown.
-     */
-    public synchronized List<String> getLockdownWhitelist() {
-        return mLockdown ? mLockdownWhitelist : null;
-    }
-
-    /**
      * Save the always-on package and lockdown config into Settings.Secure
      */
     @GuardedBy("this")
@@ -527,9 +496,6 @@
                     getAlwaysOnPackage(), mUserHandle);
             mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
                     (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
-            mSystemServices.settingsSecurePutStringForUser(
-                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
-                    String.join(",", mLockdownWhitelist), mUserHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -546,11 +512,7 @@
                     Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
             final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
                     Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
-            final String whitelistString = mSystemServices.settingsSecureGetStringForUser(
-                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle);
-            final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString)
-                    ? Collections.emptyList() : Arrays.asList(whitelistString.split(","));
-            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages);
+            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -570,7 +532,7 @@
             }
             // Remove always-on VPN if it's not supported.
             if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
-                setAlwaysOnPackage(null, false, null);
+                setAlwaysOnPackage(null, false);
                 return false;
             }
             // Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -1287,10 +1249,9 @@
     }
 
     /**
-     * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN
-     * service app itself and whitelisted packages, to only sockets that have had {@code protect()}
-     * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the
-     * kernel.
+     * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN
+     * service app itself, to only sockets that have had {@code protect()} called on them. All
+     * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel.
      *
      * The exception for the VPN UID isn't technically necessary -- setup should use protected
      * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
@@ -1306,13 +1267,8 @@
      */
     @GuardedBy("this")
     private void setVpnForcedLocked(boolean enforce) {
-        final List<String> exemptedPackages;
-        if (isNullOrLegacyVpn(mPackage)) {
-            exemptedPackages = null;
-        } else {
-            exemptedPackages = new ArrayList<>(mLockdownWhitelist);
-            exemptedPackages.add(mPackage);
-        }
+        final List<String> exemptedPackages =
+                isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
         final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
 
         Set<UidRange> addedRanges = Collections.emptySet();
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 5ed6263..e268e44 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -48,7 +48,6 @@
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.IBinder;
-import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -255,21 +254,6 @@
         }
     }
 
-    @Override
-    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-            throws RemoteException {
-        try {
-            return super.onTransact(code, data, reply, flags);
-        } catch (RuntimeException e) {
-            // The content service only throws security exceptions, so let's
-            // log all others.
-            if (!(e instanceof SecurityException)) {
-                Slog.wtf(TAG, "Content Service Crash", e);
-            }
-            throw e;
-        }
-    }
-
     /*package*/ ContentService(Context context, boolean factoryTest) {
         mContext = context;
         mFactoryTest = factoryTest;
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 58c88b3..eb0ed0a 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -19,7 +19,10 @@
 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME;
 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED;
 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT;
-
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
@@ -45,6 +48,7 @@
 import android.graphics.ColorSpace;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.ColorDisplayManager.AutoMode;
+import android.hardware.display.ColorDisplayManager.ColorMode;
 import android.hardware.display.IColorDisplayManager;
 import android.hardware.display.Time;
 import android.net.Uri;
@@ -53,6 +57,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.provider.Settings.System;
@@ -61,7 +66,6 @@
 import android.view.SurfaceControl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
-
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ColorDisplayController;
@@ -71,7 +75,6 @@
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -162,7 +165,7 @@
             }
 
             float[] displayRedGreenBlueXYZ =
-                new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+                    new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
             float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
             for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
                 displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
@@ -173,10 +176,10 @@
             }
 
             final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb(
-                "Display Color Space",
-                displayRedGreenBlueXYZ,
-                displayWhiteXYZ,
-                2.2f // gamma, unused for display white balance
+                    "Display Color Space",
+                    displayRedGreenBlueXYZ,
+                    displayWhiteXYZ,
+                    2.2f // gamma, unused for display white balance
             );
 
             float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
@@ -242,8 +245,8 @@
                 mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
 
                 mChromaticAdaptationMatrix =
-                    ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
-                            mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+                        ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                                mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
 
                 // Convert the adaptation matrix to RGB space
                 float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
@@ -385,7 +388,7 @@
      * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
      * ProgramCache for full implementation details.
      */
-    private static final float[] MATRIX_INVERT_COLOR = new float[] {
+    private static final float[] MATRIX_INVERT_COLOR = new float[]{
             0.402f, -0.598f, -0.599f, 0f,
             -1.174f, -0.174f, -1.175f, 0f,
             -0.228f, -0.228f, 0.772f, 0f,
@@ -944,6 +947,89 @@
                 .setSaturationLevel(packageName, mCurrentUser, saturationLevel);
     }
 
+    private void setColorModeInternal(@ColorMode int colorMode) {
+        if (!isColorModeAvailable(colorMode)) {
+            throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
+        }
+        System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,
+                colorMode,
+                mCurrentUser);
+    }
+
+    private @ColorMode
+    int getColorModeInternal() {
+        final ContentResolver cr = getContext().getContentResolver();
+        if (Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+                0, mCurrentUser) == 1
+                || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                0, mCurrentUser) == 1) {
+            // There are restrictions on the available color modes combined with a11y transforms.
+            if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
+                return COLOR_MODE_SATURATED;
+            } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+                return COLOR_MODE_AUTOMATIC;
+            }
+        }
+
+        int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser);
+        if (colorMode == -1) {
+            // There might be a system property controlling color mode that we need to respect; if
+            // not, this will set a suitable default.
+            colorMode = getCurrentColorModeFromSystemProperties();
+        }
+
+        // This happens when a color mode is no longer available (e.g., after system update or B&R)
+        // or the device does not support any color mode.
+        if (!isColorModeAvailable(colorMode)) {
+            if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
+                colorMode = COLOR_MODE_NATURAL;
+            } else if (colorMode == COLOR_MODE_SATURATED
+                    && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+                colorMode = COLOR_MODE_AUTOMATIC;
+            } else if (colorMode == COLOR_MODE_AUTOMATIC
+                    && isColorModeAvailable(COLOR_MODE_SATURATED)) {
+                colorMode = COLOR_MODE_SATURATED;
+            } else {
+                colorMode = -1;
+            }
+        }
+
+        return colorMode;
+    }
+
+    /**
+     * Get the current color mode from system properties, or return -1 if invalid.
+     *
+     * See {@link com.android.server.display.DisplayTransformManager}
+     */
+    private @ColorMode
+    int getCurrentColorModeFromSystemProperties() {
+        final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
+        if (displayColorSetting == 0) {
+            return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
+                    ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
+        } else if (displayColorSetting == 1) {
+            return COLOR_MODE_SATURATED;
+        } else if (displayColorSetting == 2) {
+            return COLOR_MODE_AUTOMATIC;
+        } else {
+            return -1;
+        }
+    }
+
+    private boolean isColorModeAvailable(@ColorMode int colorMode) {
+        final int[] availableColorModes = getContext().getResources().getIntArray(
+                R.array.config_availableColorModes);
+        if (availableColorModes != null) {
+            for (int mode : availableColorModes) {
+                if (mode == colorMode) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private void dumpInternal(PrintWriter pw) {
         pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
         pw.println("Night Display:");
@@ -1445,7 +1531,9 @@
      */
     public interface ColorTransformController {
 
-        /** Apply the given saturation (grayscale) matrix to the associated AppWindow. */
+        /**
+         * Apply the given saturation (grayscale) matrix to the associated AppWindow.
+         */
         void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
     }
 
@@ -1453,6 +1541,29 @@
     final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
+        public void setColorMode(int colorMode) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set display color mode");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setColorModeInternal(colorMode);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getColorMode() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getColorModeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public boolean isDeviceColorManaged() {
             final long token = Binder.clearCallingIdentity();
             try {
@@ -1640,7 +1751,9 @@
 
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+                return;
+            }
 
             final long token = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index a5e9728..b1b7d3c 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.app.ActivityTaskManager;
+import android.hardware.display.ColorDisplayManager;
 import android.opengl.Matrix;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -27,7 +28,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.ColorDisplayController;
 
 import java.util.Arrays;
 
@@ -248,20 +248,20 @@
      * work in linear space.
      */
     public static boolean needsLinearColorMatrix(int colorMode) {
-        return colorMode != ColorDisplayController.COLOR_MODE_SATURATED;
+        return colorMode != ColorDisplayManager.COLOR_MODE_SATURATED;
     }
 
     public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
-        if (colorMode == ColorDisplayController.COLOR_MODE_NATURAL) {
+        if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
             applySaturation(COLOR_SATURATION_NATURAL);
             setDisplayColor(DISPLAY_COLOR_MANAGED);
-        } else if (colorMode == ColorDisplayController.COLOR_MODE_BOOSTED) {
+        } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
             applySaturation(COLOR_SATURATION_BOOSTED);
             setDisplayColor(DISPLAY_COLOR_MANAGED);
-        } else if (colorMode == ColorDisplayController.COLOR_MODE_SATURATED) {
+        } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
             applySaturation(COLOR_SATURATION_NATURAL);
             setDisplayColor(DISPLAY_COLOR_UNMANAGED);
-        } else if (colorMode == ColorDisplayController.COLOR_MODE_AUTOMATIC) {
+        } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
             applySaturation(COLOR_SATURATION_NATURAL);
             setDisplayColor(DISPLAY_COLOR_ENHANCED);
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3fd3945..3b4e4dd 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -288,6 +288,8 @@
     private static final class DebugFlags {
         static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
                 new DebugFlag("debug.optimize_startinput", false);
+        static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
+                new DebugFlag("persist.pre_render_ime_views", false);
     }
 
     @UserIdInt
@@ -304,6 +306,7 @@
     final boolean mHasFeature;
     private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
             new ArrayMap<>();
+    private final boolean mIsLowRam;
     private final HardKeyboardListener mHardKeyboardListener;
     private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
@@ -403,6 +406,10 @@
         final ClientDeathRecipient clientDeathRecipient;
 
         boolean sessionRequested;
+        // Determines if IMEs should be pre-rendered.
+        // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
+        // through the life of the current client.
+        boolean shouldPreRenderIme;
         SessionState curSession;
 
         @Override
@@ -615,6 +622,10 @@
      * <dd>
      *   If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
      * </dd>
+     * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
+     * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
+     *    currently invisible.
+     * </dd>
      * </dl>
      * <em>Do not update this value outside of setImeWindowStatus.</em>
      */
@@ -1361,6 +1372,7 @@
         mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
         mHardKeyboardBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_externalHardKeyboardBehavior);
+        mIsLowRam = ActivityManager.isLowRamDeviceStatic();
 
         Bundle extras = new Bundle();
         extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
@@ -2264,7 +2276,10 @@
         if (mSwitchingDialog != null) return false;
         if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
                 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
-        if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false;
+        if ((visibility & InputMethodService.IME_ACTIVE) == 0
+                || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
+            return false;
+        }
         if (mWindowManagerInternal.isHardKeyboardAvailable()) {
             if (mHardKeyboardBehavior == HardKeyboardBehavior.WIRELESS_AFFORDANCE) {
                 // When physical keyboard is attached, we show the ime switcher (or notification if
@@ -2372,6 +2387,12 @@
         if (mCurToken == null) {
             return;
         }
+        if (DEBUG) {
+            Slog.d(TAG, "IME window vis: " + vis
+                    + " active: " + (vis & InputMethodService.IME_ACTIVE)
+                    + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
+        }
+
         // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
         // all updateSystemUi happens on system previlege.
         final long ident = Binder.clearCallingIdentity();
@@ -2830,6 +2851,14 @@
                 if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
                     switchUserLocked(userId);
                 }
+                // Master feature flag that overrides other conditions and forces IME preRendering.
+                if (DEBUG) {
+                    Slog.v(TAG, "IME PreRendering MASTER flag: "
+                            + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value()
+                            + ", LowRam: " + mIsLowRam);
+                }
+                // pre-rendering not supported on low-ram devices.
+                cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
 
                 if (mCurFocusedWindow == windowToken) {
                     if (DEBUG) {
@@ -3493,7 +3522,7 @@
                 try {
                     setEnabledSessionInMainThread(session);
                     session.method.startInput(startInputToken, inputContext, missingMethods,
-                            editorInfo, restarting);
+                            editorInfo, restarting, session.client.shouldPreRenderIme);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -4421,6 +4450,7 @@
         @ShellCommandResult
         private int refreshDebugProperties() {
             DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
+            DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
             return ShellCommandResult.SUCCESS;
         }
 
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index 591889d..ca9c0e0 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -19,9 +19,15 @@
 import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -55,6 +61,8 @@
     private static final String LOCATION_PERMISSION_NAME =
             "android.permission.ACCESS_FINE_LOCATION";
 
+    private static final String[] NO_LOCATION_ENABLED_PROXY_APPS = new String[0];
+
     // Wakelocks
     private static final String WAKELOCK_KEY = TAG;
     private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
@@ -66,13 +74,16 @@
     private final Handler mHandler;
     private final Context mContext;
 
+    private boolean mIsMasterLocationSettingsEnabled = true;
+    private boolean mIsOnRoamingNetwork = false;
+
     // 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 PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
-            uid -> postEvent(() -> handlePermissionsChanged(uid));
+            uid -> runOnHandler(() -> handlePermissionsChanged(uid));
 
     GnssVisibilityControl(Context context, Looper looper) {
         mContext = context;
@@ -81,8 +92,15 @@
         mHandler = new Handler(looper);
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mPackageManager = mContext.getPackageManager();
+
+        // Set to empty proxy app list initially until the configuration properties are loaded.
+        updateNfwLocationAccessProxyAppsInGnssHal();
+
+        // Listen for proxy app package installation, removal events.
+        listenForProxyAppsPackageUpdates();
+        listenForRoamingNetworkUpdate();
+
         // TODO(b/122855984): Handle global location settings on/off.
-        // TODO(b/122856189): Handle roaming case.
     }
 
     void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
@@ -90,18 +108,68 @@
         //       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.
-        postEvent(() -> handleSubscriptionOrSimChanged(nfwLocationAccessProxyApps));
+        runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
+    }
+
+    void masterLocationSettingsUpdated(boolean enabled) {
+        runOnHandler(() -> handleMasterLocationSettingsUpdated(enabled));
     }
 
     void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
             String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
             boolean inEmergencyMode, boolean isCachedLocation) {
-        postEvent(() -> handleNfwNotification(
+        runOnHandler(() -> handleNfwNotification(
                 new NfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName,
                         requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
     }
 
-    private void handleSubscriptionOrSimChanged(List<String> nfwLocationAccessProxyApps) {
+    private void listenForProxyAppsPackageUpdates() {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        intentFilter.addDataScheme("package");
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (action == null) {
+                    return;
+                }
+
+                switch (action) {
+                    case Intent.ACTION_PACKAGE_ADDED:
+                    case Intent.ACTION_PACKAGE_REMOVED:
+                    case Intent.ACTION_PACKAGE_REPLACED:
+                        String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+                        handleProxyAppPackageUpdate(pkgName, action);
+                        break;
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, mHandler);
+    }
+
+    private void handleProxyAppPackageUpdate(String pkgName, String action) {
+        final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
+        // pkgName is not one of the proxy apps in our list.
+        if (locationPermission == null) {
+            return;
+        }
+
+        Log.i(TAG, "Proxy app " + pkgName + " package changed: " + action);
+        final boolean updatedLocationPermission = hasLocationPermission(pkgName);
+        if (locationPermission != updatedLocationPermission) {
+            // Permission changed. So, update the GNSS HAL with the updated list.
+            mProxyAppToLocationPermissions.put(pkgName, updatedLocationPermission);
+            updateNfwLocationAccessProxyAppsInGnssHal();
+        }
+    }
+
+    private void handleUpdateProxyApps(List<String> nfwLocationAccessProxyApps) {
+        if (!isProxyAppListUpdated(nfwLocationAccessProxyApps)) {
+            return;
+        }
+
         if (nfwLocationAccessProxyApps.isEmpty()) {
             // Stop listening for app permission changes. Clear the app list in GNSS HAL.
             if (!mProxyAppToLocationPermissions.isEmpty()) {
@@ -125,6 +193,27 @@
         updateNfwLocationAccessProxyAppsInGnssHal();
     }
 
+    private boolean isProxyAppListUpdated(List<String> nfwLocationAccessProxyApps) {
+        if (nfwLocationAccessProxyApps.size() != mProxyAppToLocationPermissions.size()) {
+            return true;
+        }
+
+        for (String nfwLocationAccessProxyApp : nfwLocationAccessProxyApps) {
+            if (!mProxyAppToLocationPermissions.containsKey(nfwLocationAccessProxyApp)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private void handleMasterLocationSettingsUpdated(boolean enabled) {
+        mIsMasterLocationSettingsEnabled = enabled;
+        Log.i(TAG, "Master location settings switch changed to "
+                + (enabled ? "enabled" : "disabled"));
+        updateNfwLocationAccessProxyAppsInGnssHal();
+    }
+
     // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
     private static class NfwNotification {
         private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
@@ -149,7 +238,7 @@
         private final boolean mInEmergencyMode;
         private final boolean mIsCachedLocation;
 
-        NfwNotification(String proxyAppPackageName, byte protocolStack,
+        private NfwNotification(String proxyAppPackageName, byte protocolStack,
                 String otherProtocolStackName, byte requestor, String requestorId,
                 byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
             mProxyAppPackageName = proxyAppPackageName;
@@ -162,7 +251,7 @@
             mIsCachedLocation = isCachedLocation;
         }
 
-        void copyFieldsToIntent(Intent intent) {
+        private void copyFieldsToIntent(Intent intent) {
             intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
             if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
                 intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
@@ -188,7 +277,7 @@
                     mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
         }
 
-        String getResponseTypeAsString() {
+        private String getResponseTypeAsString() {
             switch (mResponseType) {
                 case NFW_RESPONSE_TYPE_REJECTED:
                     return "REJECTED";
@@ -246,6 +335,24 @@
     }
 
     private void updateNfwLocationAccessProxyAppsInGnssHal() {
+        final String[] locationPermissionEnabledProxyApps = shouldDisableNfwLocationAccess()
+                ? NO_LOCATION_ENABLED_PROXY_APPS : getLocationPermissionEnabledProxyApps();
+        final String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
+        Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+                + proxyAppsStr);
+        boolean result = native_enable_nfw_location_access(locationPermissionEnabledProxyApps);
+        if (!result) {
+            Log.e(TAG, "Failed to update non-framework location access proxy apps in the"
+                    + " GNSS HAL to: " + proxyAppsStr);
+        }
+    }
+
+    private boolean shouldDisableNfwLocationAccess() {
+        // TODO(b/122856189): Add disableWhenRoaming configuration per proxy app.
+        return mIsOnRoamingNetwork || !mIsMasterLocationSettingsEnabled;
+    }
+
+    private String[] getLocationPermissionEnabledProxyApps() {
         // Get a count of proxy apps with location permission enabled to array creation size.
         int countLocationPermissionEnabledProxyApps = 0;
         for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
@@ -264,15 +371,7 @@
                 locationPermissionEnabledProxyApps[i++] = proxyApp;
             }
         }
-
-        String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
-        Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
-                + proxyAppsStr);
-        boolean result = native_enable_nfw_location_access(locationPermissionEnabledProxyApps);
-        if (!result) {
-            Log.e(TAG, "Failed to update non-framework location access proxy apps in the"
-                    + " GNSS HAL to: " + proxyAppsStr);
-        }
+        return locationPermissionEnabledProxyApps;
     }
 
     private void handleNfwNotification(NfwNotification nfwNotification) {
@@ -360,7 +459,31 @@
                 isPermissionMismatched);
     }
 
-    private void postEvent(Runnable event) {
+    private void listenForRoamingNetworkUpdate() {
+        // Register for network capabilities changes to monitor roaming changes.
+        ConnectivityManager mConnMgr = (ConnectivityManager) mContext.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+        networkRequestBuilder.addCapability(NetworkCapabilities.TRANSPORT_CELLULAR);
+        NetworkRequest networkRequest = networkRequestBuilder.build();
+        mConnMgr.registerNetworkCallback(networkRequest,
+                new ConnectivityManager.NetworkCallback() {
+                    @Override
+                    public void onCapabilitiesChanged(Network network,
+                            NetworkCapabilities capabilities) {
+                        boolean isRoaming = !capabilities.hasTransport(
+                                NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+                        // No locking required for this test and set because the callback
+                        // runs in mHandler thread.
+                        if (mIsOnRoamingNetwork != isRoaming) {
+                            mIsOnRoamingNetwork = isRoaming;
+                            updateNfwLocationAccessProxyAppsInGnssHal();
+                        }
+                    }
+                }, mHandler);
+    }
+
+    private void runOnHandler(Runnable event) {
         // Hold a wake lock until this message is delivered.
         // Note that this assumes the message will not be removed from the queue before
         // it is handled (otherwise the wake lock would be leaked).
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9100f6a..6eff815 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -449,8 +449,7 @@
 
     private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
 
-    private static final boolean PRECOMPILED_LAYOUT_ENABLED =
-            SystemProperties.getBoolean("view.precompiled_layout_enabled", false);
+    private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -9119,7 +9118,7 @@
                 pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
             }
 
-            if (PRECOMPILED_LAYOUT_ENABLED) {
+            if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                 mArtManagerService.compileLayouts(pkg);
             }
 
@@ -16211,7 +16210,7 @@
 
             if (performDexopt) {
                 // Compile the layout resources.
-                if (PRECOMPILED_LAYOUT_ENABLED) {
+                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
                     mViewCompiler.compileLayouts(pkg);
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 563fd7f..84c8b60 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -690,6 +690,10 @@
         return result;
     }
 
+    public boolean hasShareTargets() {
+        return !mShareTargets.isEmpty();
+    }
+
     /**
      * Return the filenames (excluding path names) of icon bitmap files from this package.
      */
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index fdbaba2..792b34c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2167,6 +2167,19 @@
         }
     }
 
+    @Override
+    public boolean hasShareTargets(String packageName, String packageToCheck,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        enforceSystem();
+
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            return getPackageShortcutsLocked(packageToCheck, userId).hasShareTargets();
+        }
+    }
+
     @GuardedBy("mLock")
     private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
             @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 8d64b81..2455113 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -16,6 +16,10 @@
 
 package com.android.server.pm;
 
+import com.google.android.collect.Sets;
+
+import com.android.internal.util.Preconditions;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -38,10 +42,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
-import com.android.internal.util.Preconditions;
-
-import com.google.android.collect.Sets;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
@@ -666,7 +666,6 @@
 
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_APP:
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN:
-            case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST:
                 // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn
                 final int appId = UserHandle.getAppId(callingUid);
                 if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0e40a00..13c4d88 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2569,6 +2569,7 @@
     }
 
     private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
+            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
             WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
             WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
         };
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e1a911e..1d82970 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -825,16 +825,16 @@
                 // like the ANR / app crashed dialogs
                 return  canAddInternalSystemWindow ? 11 : 10;
             case TYPE_APPLICATION_OVERLAY:
-                return  12;
+                return  canAddInternalSystemWindow ? 13 : 12;
             case TYPE_DREAM:
                 // used for Dreams (screensavers with TYPE_DREAM windows)
-                return  13;
+                return  14;
             case TYPE_INPUT_METHOD:
                 // on-screen keyboards and other such input method user interfaces go here.
-                return  14;
+                return  15;
             case TYPE_INPUT_METHOD_DIALOG:
                 // on-screen keyboards and other such input method user interfaces go here.
-                return  15;
+                return  16;
             case TYPE_STATUS_BAR:
                 return  17;
             case TYPE_STATUS_BAR_PANEL:
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 055c941..7f2dedb 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.app.role.RoleManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.Debug;
 import android.provider.Settings;
@@ -90,6 +91,17 @@
 
                 return CollectionUtils.singletonOrEmpty(result);
             }
+            case RoleManager.ROLE_ASSISTANT: {
+                String legacyAssistant = Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
+
+                if (legacyAssistant == null || legacyAssistant.isEmpty()) {
+                    return Collections.emptyList();
+                } else {
+                    return Collections.singletonList(
+                            ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+                }
+            }
             default: {
                 Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
                 return Collections.emptyList();
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c0517fd..1c7596b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -198,6 +198,7 @@
             // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
             // for a given role before adding a migration statement for it here
             migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+            migrateRoleIfNecessary(RoleManager.ROLE_ASSISTANT, userId);
 
             // Some vital packages state has changed since last role grant
             // Run grants again
diff --git a/services/core/java/com/android/server/rollback/LocalIntentReceiver.java b/services/core/java/com/android/server/rollback/LocalIntentReceiver.java
new file mode 100644
index 0000000..504a349
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/LocalIntentReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.os.IBinder;
+
+import java.util.function.Consumer;
+
+/** {@code IntentSender} implementation for RollbackManager internal use. */
+class LocalIntentReceiver {
+    final Consumer<Intent> mConsumer;
+
+    LocalIntentReceiver(Consumer<Intent> consumer) {
+        mConsumer = consumer;
+    }
+
+    private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+        @Override
+        public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+                IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+            mConsumer.accept(intent);
+        }
+    };
+
+    public IntentSender getIntentSender() {
+        return new IntentSender((IIntentSender) mLocalSender);
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 693d5d6..8b4c410 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -19,8 +19,6 @@
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -36,11 +34,9 @@
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.storage.StorageManager;
@@ -66,7 +62,6 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
-import java.util.function.Consumer;
 
 /**
  * Implementation of service that manages APK level rollbacks.
@@ -116,6 +111,7 @@
     private final Context mContext;
     private final HandlerThread mHandlerThread;
     private final Installer mInstaller;
+    private final RollbackPackageHealthObserver mPackageHealthObserver;
 
     RollbackManagerServiceImpl(Context context) {
         mContext = context;
@@ -128,6 +124,8 @@
 
         mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
 
+        mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
+
         // Kick off loading of the rollback data from strorage in a background
         // thread.
         // TODO: Consider loading the rollback data directly here instead, to
@@ -376,28 +374,32 @@
 
             final LocalIntentReceiver receiver = new LocalIntentReceiver(
                     (Intent result) -> {
-                        // We've now completed the rollback, so we mark it as no longer in
-                        // progress.
-                        data.inProgress = false;
+                        getHandler().post(() -> {
+                            // We've now completed the rollback, so we mark it as no longer in
+                            // progress.
+                            data.inProgress = false;
 
-                        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                                PackageInstaller.STATUS_FAILURE);
-                        if (status != PackageInstaller.STATUS_SUCCESS) {
-                            sendFailure(statusReceiver, "Rollback downgrade install failed: "
-                                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
-                            return;
-                        }
+                            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                                    PackageInstaller.STATUS_FAILURE);
+                            if (status != PackageInstaller.STATUS_SUCCESS) {
+                                sendFailure(statusReceiver,
+                                        "Rollback downgrade install failed: "
+                                        + result.getStringExtra(
+                                                PackageInstaller.EXTRA_STATUS_MESSAGE));
+                                return;
+                            }
 
-                        addRecentlyExecutedRollback(rollback);
-                        sendSuccess(statusReceiver);
+                            addRecentlyExecutedRollback(rollback);
+                            sendSuccess(statusReceiver);
 
-                        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+                            Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
 
-                        // TODO: This call emits the warning "Calling a method in the
-                        // system process without a qualified user". Fix that.
-                        // TODO: Limit this to receivers holding the
-                        // MANAGE_ROLLBACKS permission?
-                        mContext.sendBroadcast(broadcast);
+                            // TODO: This call emits the warning "Calling a method in the
+                            // system process without a qualified user". Fix that.
+                            // TODO: Limit this to receivers holding the
+                            // MANAGE_ROLLBACKS permission?
+                            mContext.sendBroadcast(broadcast);
+                        });
                     }
             );
 
@@ -820,26 +822,6 @@
         });
     }
 
-    private class LocalIntentReceiver {
-        final Consumer<Intent> mConsumer;
-
-        LocalIntentReceiver(Consumer<Intent> consumer) {
-            mConsumer = consumer;
-        }
-
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-            @Override
-            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-                getHandler().post(() -> mConsumer.accept(intent));
-            }
-        };
-
-        public IntentSender getIntentSender() {
-            return new IntentSender((IIntentSender) mLocalSender);
-        }
-    }
-
     /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
@@ -906,7 +888,17 @@
                             ensureRollbackDataLoadedLocked();
                             mAvailableRollbacks.add(data);
                         }
-
+                        // TODO(zezeozue): Provide API to explicitly start observing instead
+                        // of doing this for all rollbacks. If we do this for all rollbacks,
+                        // should document in PackageInstaller.SessionParams#setEnableRollback
+                        // After enabling and commiting any rollback, observe packages and
+                        // prepare to rollback if packages crashes too frequently.
+                        List<String> packages = new ArrayList<>();
+                        for (int i = 0; i < data.packages.size(); i++) {
+                            packages.add(data.packages.get(i).getPackageName());
+                        }
+                        mPackageHealthObserver.startObservingHealth(packages,
+                                ROLLBACK_LIFETIME_DURATION_MILLIS);
                         scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                     } catch (IOException e) {
                         Log.e(TAG, "Unable to enable rollback", e);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
new file mode 100644
index 0000000..1f2f1cc
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+
+import java.util.List;
+
+/**
+ * {@code PackageHealthObserver} for {@code RollbackManagerService}.
+ *
+ * @hide
+ */
+public final class RollbackPackageHealthObserver implements PackageHealthObserver {
+    private static final String TAG = "RollbackPackageHealthObserver";
+    private static final String NAME = "rollback-observer";
+    private Context mContext;
+    private Handler mHandler;
+
+    RollbackPackageHealthObserver(Context context) {
+        mContext = context;
+        HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
+        handlerThread.start();
+        mHandler = handlerThread.getThreadHandler();
+        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
+    }
+
+    @Override
+    public boolean onHealthCheckFailed(String packageName) {
+        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
+        if (rollback != null) {
+            // TODO(zezeozue): Only rollback if rollback version == failed package version
+            mHandler.post(() -> executeRollback(rollbackManager, rollback));
+            return true;
+        }
+        // Don't handle the notification, no rollbacks available
+        return false;
+    }
+
+    /**
+     * Start observing health of {@code packages} for {@code durationMs}.
+     * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
+     */
+    public void startObservingHealth(List<String> packages, long durationMs) {
+        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
+    }
+
+    private void executeRollback(RollbackManager manager, RollbackInfo rollback) {
+        // TODO(zezeozue): Log initiated metrics
+        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
+            mHandler.post(() -> {
+                int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
+                if (status == PackageInstaller.STATUS_SUCCESS) {
+                    // TODO(zezeozue); Log success metrics
+                    // Rolledback successfully, no action required by other observers
+                } else {
+                    // TODO(zezeozue); Log failure metrics
+                    // Rollback failed other observers should have a shot
+                }
+            });
+        });
+        manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 891c3da..3a754c4 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2286,7 +2286,7 @@
      * Check if the display to which this stack is attached has
      * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
      */
-    private boolean canShowWithInsecureKeyguard() {
+    boolean canShowWithInsecureKeyguard() {
         final ActivityDisplay activityDisplay = getDisplay();
         if (activityDisplay == null) {
             throw new IllegalStateException("Stack is not attached to any display, stackId="
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 865ffbd..3a077b8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -916,7 +916,8 @@
             PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
             Intent intent) {
         // don't abort for the most important UIDs
-        if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+        if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
+                || callingUid == Process.NFC_UID) {
             return false;
         }
         // don't abort if the callerApp has any visible activity
@@ -924,14 +925,15 @@
             return false;
         }
         // don't abort if the callingUid is in the foreground or is a persistent system process
-        final boolean isCallingUidForeground = isUidForeground(callingUid);
+        final boolean isCallingUidForeground = mService.isUidForeground(callingUid);
         final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
                 callingUid);
         if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
             return false;
         }
         // take realCallingUid into consideration
-        final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+        final boolean isRealCallingUidForeground = mService.isUidForeground(
+                realCallingUid);
         final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
                 realCallingUid);
         if (realCallingUid != callingUid) {
@@ -976,12 +978,6 @@
         return true;
     }
 
-    /** Returns true if uid has a visible window or its process is in a top state. */
-    private boolean isUidForeground(int uid) {
-        return (mService.getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
-            || mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
-    }
-
     /** Returns true if uid is in a persistent state. */
     private boolean isUidPersistentSystemProcess(int uid) {
         return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 67b00b2..1a5e6a1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -489,4 +489,7 @@
      */
     public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
             boolean reducedResolution);
+
+    /** Returns true if uid has a visible window or its process is in a top state. */
+    public abstract boolean isUidForeground(int uid);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ea6f4cc..5fabde4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4399,6 +4399,27 @@
         }
     }
 
+    @Override
+    public void registerRemoteAnimationsForDisplay(int displayId,
+            RemoteAnimationDefinition definition) {
+        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "registerRemoteAnimations");
+        definition.setCallingPid(Binder.getCallingPid());
+        synchronized (mGlobalLock) {
+            final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
+            if (display == null) {
+                Slog.e(TAG, "Couldn't find display with id: " + displayId);
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                display.mDisplayContent.registerRemoteAnimations(definition);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
     /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
     @Override
     public void alwaysShowUnsupportedCompileSdkWarning(ComponentName activity) {
@@ -5632,6 +5653,11 @@
         return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
     }
 
+    boolean isUidForeground(int uid) {
+        return (getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+                || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
+    }
+
     /**
      * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
      * the whitelist
@@ -7041,5 +7067,12 @@
                 return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
             }
         }
+
+        @Override
+        public boolean isUidForeground(int uid) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.isUidForeground(uid);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 49308b8..8f0a7c0 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -76,6 +76,7 @@
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private final WallpaperController mWallpaperControllerLocked;
+    private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
 
     private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
 
@@ -85,6 +86,10 @@
         mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
     }
 
+    void registerRemoteAnimations(RemoteAnimationDefinition definition) {
+        mRemoteAnimationDefinition = definition;
+    }
+
     /**
      * Handle application transition for given display.
      */
@@ -216,6 +221,21 @@
         return mainWindow != null ? mainWindow.mAttrs : null;
     }
 
+    RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
+            ArraySet<Integer> activityTypes) {
+        final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
+        if (definition != null) {
+            final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
+            if (adapter != null) {
+                return adapter;
+            }
+        }
+        if (mRemoteAnimationDefinition == null) {
+            return null;
+        }
+        return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
+    }
+
     /**
      * Overrides the pending transition with the remote animation defined for the transition in the
      * set of defined remote animations in the app window token.
@@ -229,11 +249,8 @@
         if (animLpToken == null) {
             return;
         }
-        final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
-        if (definition == null) {
-            return;
-        }
-        final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
+        final RemoteAnimationAdapter adapter =
+                getRemoteAnimationOverride(animLpToken, transit, activityTypes);
         if (adapter != null) {
             animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
                     adapter);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 65b36a0..d915e10 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -105,6 +105,7 @@
 import android.view.DisplayInfo;
 import android.view.IApplicationToken;
 import android.view.InputApplicationHandle;
+import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
@@ -1621,6 +1622,17 @@
         t.reparent(getSurfaceControl(), mTransitChangeLeash);
         onAnimationLeashCreated(t, mTransitChangeLeash);
 
+        // Skip creating snapshot if this transition is controlled by a remote animator which
+        // doesn't need it.
+        ArraySet<Integer> activityTypes = new ArraySet<>();
+        activityTypes.add(getActivityType());
+        RemoteAnimationAdapter adapter =
+                mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
+                        this, TRANSIT_TASK_CHANGE_WINDOWING_MODE, activityTypes);
+        if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
+            return;
+        }
+
         if (mThumbnail == null && getTask() != null) {
             final TaskSnapshotController snapshotCtrl = mWmService.mTaskSnapshotController;
             final ArraySet<Task> tasks = new ArraySet<>();
@@ -1639,6 +1651,11 @@
         return mTransitChangeLeash != null || isChangeTransition(mTransit);
     }
 
+    @VisibleForTesting
+    AppWindowThumbnail getThumbnail() {
+        return mThumbnail;
+    }
+
     @Override
     void checkAppWindowsReadyToShow() {
         if (allDrawn == mLastAllDrawn) {
@@ -2349,7 +2366,7 @@
             AnimationAdapter thumbnailAdapter = null;
             getAnimationBounds(mTmpPoint, mTmpRect);
 
-            boolean isChanging = isChangeTransition(transit) && mThumbnail != null;
+            boolean isChanging = isChangeTransition(transit) && enter;
 
             // Delaying animation start isn't compatible with remote animations at all.
             if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
@@ -2368,11 +2385,13 @@
                                 getDisplayContent().getDisplayInfo(), duration,
                                 true /* isAppAnimation */, false /* isThumbnail */),
                         mWmService.mSurfaceAnimationRunner);
-                thumbnailAdapter = new LocalAnimationAdapter(
-                        new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
-                                getDisplayContent().getDisplayInfo(), duration,
-                                true /* isAppAnimation */, true /* isThumbnail */),
-                        mWmService.mSurfaceAnimationRunner);
+                if (mThumbnail != null) {
+                    thumbnailAdapter = new LocalAnimationAdapter(
+                            new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
+                                    getDisplayContent().getDisplayInfo(), duration,
+                                    true /* isAppAnimation */, true /* isThumbnail */),
+                            mWmService.mSurfaceAnimationRunner);
+                }
                 mTransit = transit;
                 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
             } else {
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 650d0be..ce3fb51 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -41,6 +41,8 @@
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -522,6 +524,11 @@
         mChangeListeners.remove(listener);
     }
 
+    @VisibleForTesting
+    boolean containsListener(ConfigurationContainerListener listener) {
+        return mChangeListeners.contains(listener);
+    }
+
     /**
      * Must be called when new parent for the container was set.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8f976e7..7a9ff52 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -162,6 +162,7 @@
 import android.view.InputDevice;
 import android.view.InsetsState.InternalInsetType;
 import android.view.MagnificationSpec;
+import android.view.RemoteAnimationDefinition;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
@@ -1056,11 +1057,6 @@
      */
     void setInsetProvider(@InternalInsetType int type, WindowState win,
             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
-        if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL) {
-            if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) {
-                return;
-            }
-        }
         mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider);
     }
 
@@ -1091,6 +1087,10 @@
         return mLastWindowForcedOrientation;
     }
 
+    void registerRemoteAnimations(RemoteAnimationDefinition definition) {
+        mAppTransitionController.registerRemoteAnimations(definition);
+    }
+
     /**
      * Temporarily pauses rotation changes until resumed.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6d3c693..4006332 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -58,6 +58,7 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -2029,7 +2030,8 @@
                     of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
-                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
+                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT
+                        || type == TYPE_APPLICATION_OVERLAY) {
                     // These dialogs are stable to interim decor changes.
                     cf.set(displayFrames.mStable);
                     of.set(displayFrames.mStable);
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index e49e4c0..e798203 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -16,7 +16,13 @@
 
 package com.android.server.wm;
 
+import static android.view.InsetsState.TYPE_IME;
+import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.ViewRootImpl.sNewInsetsMode;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -59,6 +65,7 @@
      */
     private boolean mServerVisible;
 
+    private final boolean mControllable;
 
     InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
             DisplayContent displayContent) {
@@ -66,6 +73,15 @@
         mSource = source;
         mDisplayContent = displayContent;
         mStateController = stateController;
+
+        final int type = source.getType();
+        if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) {
+            mControllable = sNewInsetsMode == NEW_INSETS_MODE_FULL;
+        } else if (type == TYPE_IME) {
+            mControllable = sNewInsetsMode >= NEW_INSETS_MODE_IME;
+        } else {
+            mControllable = false;
+        }
     }
 
     InsetsSource getSource() {
@@ -73,6 +89,13 @@
     }
 
     /**
+     * @return Whether the current flag configuration allows to control this source.
+     */
+    boolean isControllable() {
+        return mControllable;
+    }
+
+    /**
      * Updates the window that currently backs this source.
      *
      * @param win The window that links to this source.
@@ -91,6 +114,9 @@
             mSource.setFrame(new Rect());
         } else {
             mWin.setInsetProvider(this);
+            if (mControllingWin != null) {
+                updateControlForTarget(mControllingWin, true /* force */);
+            }
         }
     }
 
@@ -113,8 +139,12 @@
                 && !mWin.mGivenInsetsPending);
     }
 
-    void updateControlForTarget(@Nullable WindowState target) {
-        if (target == mControllingWin) {
+    void updateControlForTarget(@Nullable WindowState target, boolean force) {
+        if (mWin == null) {
+            mControllingWin = target;
+            return;
+        }
+        if (target == mControllingWin && !force) {
             return;
         }
         if (target == null) {
@@ -161,7 +191,7 @@
     }
 
     boolean isClientVisible() {
-        return ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
+        return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
     }
 
     private class ControlAdapter implements AnimationAdapter {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 32dbe96..bb0cbb1 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -163,18 +163,18 @@
     }
 
     private void onControlChanged(int type, @Nullable WindowState win) {
-        if (sNewInsetsMode == NEW_INSETS_MODE_NONE) {
-            return;
-        }
         final WindowState previous = mTypeWinControlMap.get(type);
         if (win == previous) {
             return;
         }
-        final InsetsSourceProvider controller = mControllers.get(type);
+        final InsetsSourceProvider controller = getSourceProvider(type);
         if (controller == null) {
             return;
         }
-        controller.updateControlForTarget(win);
+        if (!controller.isControllable()) {
+            return;
+        }
+        controller.updateControlForTarget(win, false /* force */);
         if (previous != null) {
             removeFromControlMaps(previous, type);
             mPendingControlChanged.add(previous);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 177f244..b5be2ac5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -91,9 +91,7 @@
      */
     boolean isKeyguardOrAodShowing(int displayId) {
         return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
-                && (displayId == DEFAULT_DISPLAY
-                        ? !isDisplayOccluded(DEFAULT_DISPLAY)
-                        : isShowingOnSecondaryDisplay(displayId));
+                && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -101,10 +99,7 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway
-                && (displayId == DEFAULT_DISPLAY
-                        ? !isDisplayOccluded(DEFAULT_DISPLAY)
-                        : isShowingOnSecondaryDisplay(displayId));
+        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
     }
 
     /**
@@ -152,14 +147,6 @@
         updateKeyguardSleepToken();
     }
 
-    private boolean isShowingOnSecondaryDisplay(int displayId) {
-        if (mSecondaryDisplayIdsShowing == null) return false;
-        for (int showingId : mSecondaryDisplayIdsShowing) {
-            if (displayId == showingId) return true;
-        }
-        return false;
-    }
-
     /**
      * Called when Keyguard is going away.
      *
@@ -473,8 +460,16 @@
                 if (stack.getTopDismissingKeyguardActivity() != null) {
                     mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
                 }
+                // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
+                if (mDisplayId != DEFAULT_DISPLAY) {
+                    mOccluded |= stack.canShowWithInsecureKeyguard()
+                            && controller.canDismissKeyguard();
+                }
             }
-            mOccluded |= controller.mWindowManager.isShowingDream();
+            // TODO(b/123372519): isShowingDream can only works on default display.
+            if (mDisplayId == DEFAULT_DISPLAY) {
+                mOccluded |= controller.mWindowManager.isShowingDream();
+            }
 
             // TODO(b/113840485): Handle app transition for individual display, and apply occluded
             // state change to secondary displays.
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index f760b39..5f95691 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -322,8 +322,10 @@
                 mStartBounds = new Rect(startBounds);
                 mTmpRect.set(startBounds);
                 mTmpRect.offsetTo(0, 0);
-                mThumbnailAdapter =
-                        new RemoteAnimationAdapterWrapper(this, new Point(0, 0), mTmpRect);
+                if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
+                    mThumbnailAdapter =
+                            new RemoteAnimationAdapterWrapper(this, new Point(0, 0), mTmpRect);
+                }
             } else {
                 mStartBounds = null;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5eff7d8..e6581df 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2817,7 +2817,7 @@
 
     public boolean isShowingDream() {
         synchronized (mGlobalLock) {
-            // TODO: fix this when dream can be shown on non-default display.
+            // TODO(b/123372519): Fix this when dream can be shown on non-default display.
             return getDefaultDisplayContentLocked().getDisplayPolicy().isShowingDreamLw();
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c38a974..030ee09 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -52,6 +52,7 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.Watchdog;
@@ -330,6 +331,13 @@
         return mRequiredAbi;
     }
 
+    /** Returns ID of display overriding the configuration for this process, or
+     *  INVALID_DISPLAY if no display is overriding. */
+    @VisibleForTesting
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
     public void setDebugging(boolean debugging) {
         mDebugging = debugging;
     }
@@ -761,15 +769,15 @@
         activityDisplay.registerConfigurationChangeListener(this);
     }
 
-    private void unregisterDisplayConfigurationListenerLocked() {
+    @VisibleForTesting
+    void unregisterDisplayConfigurationListenerLocked() {
         if (mDisplayId == INVALID_DISPLAY) {
             return;
         }
         final ActivityDisplay activityDisplay =
                 mAtm.mRootActivityContainer.getActivityDisplay(mDisplayId);
         if (activityDisplay != null) {
-            mAtm.mRootActivityContainer.getActivityDisplay(
-                    mDisplayId).unregisterConfigurationChangeListener(this);
+            activityDisplay.unregisterConfigurationChangeListener(this);
         }
         mDisplayId = INVALID_DISPLAY;
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ce5eb84..4f12010 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4367,6 +4367,12 @@
     }
 
     void startAnimation(Animation anim) {
+
+        // If we are an inset provider, all our animations are driven by the inset client.
+        if (mInsetProvider != null && mInsetProvider.isControllable()) {
+            return;
+        }
+
         final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
         anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
                 displayInfo.appWidth, displayInfo.appHeight);
@@ -4380,6 +4386,12 @@
     }
 
     private void startMoveAnimation(int left, int top) {
+
+        // If we are an inset provider, all our animations are driven by the inset client.
+        if (mInsetProvider != null && mInsetProvider.isControllable()) {
+            return;
+        }
+
         if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
         final Point oldPosition = new Point();
         final Point newPosition = new Point();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab53242..f79f9bc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -70,17 +70,24 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
+import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+
 import static android.provider.Telephony.Carriers.DPC_URI;
 import static android.provider.Telephony.Carriers.ENFORCE_KEY;
 import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
 
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
+        .PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
+        .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+
 import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
 import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
+
+
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -233,11 +240,11 @@
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.StatLogger;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+import com.android.internal.util.StatLogger;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
@@ -1918,11 +1925,7 @@
         }
 
         AlarmManager getAlarmManager() {
-            return mContext.getSystemService(AlarmManager.class);
-        }
-
-        ConnectivityManager getConnectivityManager() {
-            return mContext.getSystemService(ConnectivityManager.class);
+            return (AlarmManager) mContext.getSystemService(AlarmManager.class);
         }
 
         IWindowManager getIWindowManager() {
@@ -6305,8 +6308,7 @@
      * @throws UnsupportedOperationException if the package does not support being set as always-on.
      */
     @Override
-    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
-            List<String> lockdownWhitelist)
+    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
             throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
 
@@ -6314,23 +6316,11 @@
         final long token = mInjector.binderClearCallingIdentity();
         try {
             if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
-                Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
-                throw new ServiceSpecificException(
-                        DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage);
+                return false;
             }
-
-            if (vpnPackage != null && lockdown && lockdownWhitelist != null) {
-                for (String packageName : lockdownWhitelist) {
-                    if (!isPackageInstalledForUser(packageName, userId)) {
-                        Slog.w(LOG_TAG, "Non-existent package in VPN whitelist: " + packageName);
-                        throw new ServiceSpecificException(
-                                DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName);
-                    }
-                }
-            }
-            // If some package is uninstalled after the check above, it will be ignored by CM.
-            if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser(
-                    userId, vpnPackage, lockdown, lockdownWhitelist)) {
+            ConnectivityManager connectivityManager = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdown)) {
                 throw new UnsupportedOperationException();
             }
             DevicePolicyEventLogger
@@ -6347,40 +6337,16 @@
     }
 
     @Override
-    public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException {
-        enforceProfileOrDeviceOwner(admin);
-
-        final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
-        enforceProfileOrDeviceOwner(admin);
-
-        final int userId = mInjector.userHandleGetCallingUserId();
-        final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().isVpnLockdownEnabled(userId);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
+    public String getAlwaysOnVpnPackage(ComponentName admin)
             throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
-        try {
-            return mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId);
+        try{
+            ConnectivityManager connectivityManager = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            return connectivityManager.getAlwaysOnVpnPackageForUser(userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
@@ -6405,7 +6371,7 @@
         }
     }
 
-    private void forceWipeUser(int userId, String wipeReasonForUser) {
+    private void forceWipeUser(int userId, String wipeReasonForUser, boolean wipeSilently) {
         boolean success = false;
         try {
             IActivityManager am = mInjector.getIActivityManager();
@@ -6416,7 +6382,7 @@
             success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
             if (!success) {
                 Slog.w(LOG_TAG, "Couldn't remove user " + userId);
-            } else if (isManagedProfile(userId) && !TextUtils.isEmpty(wipeReasonForUser)) {
+            } else if (isManagedProfile(userId) && !wipeSilently) {
                 sendWipeProfileNotification(wipeReasonForUser);
             }
         } catch (RemoteException re) {
@@ -6431,6 +6397,7 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkStringNotEmpty(wipeReasonForUser, "wipeReasonForUser is null or empty");
         enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
 
         final ActiveAdmin admin;
@@ -6490,7 +6457,7 @@
                         internalReason,
                         /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
             } else {
-                forceWipeUser(userId, wipeReasonForUser);
+                forceWipeUser(userId, wipeReasonForUser, (flags & WIPE_SILENTLY) != 0);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -6852,7 +6819,9 @@
         enforceDeviceOwner(who);
         long token = mInjector.binderClearCallingIdentity();
         try {
-            mInjector.getConnectivityManager().setGlobalProxy(proxyInfo);
+            ConnectivityManager connectivityManager = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            connectivityManager.setGlobalProxy(proxyInfo);
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 65eaf554..5861368 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1561,6 +1561,12 @@
                 traceEnd();
             }
 
+            // Grants default permissions and defines roles
+            traceBeginAndSlog("StartRoleManagerService");
+            mSystemServiceManager.startService(new RoleManagerService(
+                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
+            traceEnd();
+
             // We need to always start this service, regardless of whether the
             // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
             // of initializing various settings.  It will internally modify its behavior
@@ -2011,12 +2017,6 @@
             }
             traceEnd();
 
-            // Grants default permissions and defines roles
-            traceBeginAndSlog("StartRoleManagerService");
-            mSystemServiceManager.startService(new RoleManagerService(
-                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
-            traceEnd();
-
             // No dependency on Webview preparation in system server. But this should
             // be completed before allowing 3rd party
             final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
diff --git a/services/net/java/android/net/shared/NetworkObserverRegistry.java b/services/net/java/android/net/shared/NetworkObserverRegistry.java
new file mode 100644
index 0000000..36945f5
--- /dev/null
+++ b/services/net/java/android/net/shared/NetworkObserverRegistry.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.shared;
+
+import static android.Manifest.permission.NETWORK_STACK;
+
+import android.content.Context;
+import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
+import android.net.INetworkManagementEventObserver;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+/**
+ * A class for reporting network events to clients.
+ *
+ * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to
+ * all INetworkManagementEventObserver objects that have registered with it.
+ *
+ * TODO: Make the notifyXyz methods protected once subclasses (e.g., the NetworkManagementService
+ * subclass) no longer call them directly.
+ *
+ * TODO: change from RemoteCallbackList to direct in-process callbacks.
+ */
+public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {
+
+    private final Context mContext;
+    private final Handler mDaemonHandler;
+    private static final String TAG = "NetworkObserverRegistry";
+
+    /**
+     * Constructs a new instance and registers it with netd.
+     * This method should only be called once since netd will reject multiple registrations from
+     * the same process.
+     */
+    public NetworkObserverRegistry(Context context, Handler handler, INetd netd)
+            throws RemoteException {
+        mContext = context;
+        mDaemonHandler = handler;
+        netd.registerUnsolicitedEventListener(this);
+    }
+
+    private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
+            new RemoteCallbackList<>();
+
+    /**
+     * Registers the specified observer and start sending callbacks to it.
+     * This method may be called on any thread.
+     */
+    public void registerObserver(INetworkManagementEventObserver observer) {
+        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        mObservers.register(observer);
+    }
+
+    /**
+     * Unregisters the specified observer and stop sending callbacks to it.
+     * This method may be called on any thread.
+     */
+    public void unregisterObserver(INetworkManagementEventObserver observer) {
+        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        mObservers.unregister(observer);
+    }
+
+    @FunctionalInterface
+    private interface NetworkManagementEventCallback {
+        void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
+    }
+
+    private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
+        final int length = mObservers.beginBroadcast();
+        try {
+            for (int i = 0; i < length; i++) {
+                try {
+                    eventCallback.sendCallback(mObservers.getBroadcastItem(i));
+                } catch (RemoteException | RuntimeException e) {
+                }
+            }
+        } finally {
+            mObservers.finishBroadcast();
+        }
+    }
+
+    /**
+     * Notify our observers of a change in the data activity state of the interface
+     */
+    public void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
+            int uid, boolean fromRadio) {
+        invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
+                Integer.toString(type), isActive, tsNanos));
+    }
+
+    @Override
+    public void onInterfaceClassActivityChanged(boolean isActive,
+            int label, long timestamp, int uid) throws RemoteException {
+        final long timestampNanos;
+        if (timestamp <= 0) {
+            timestampNanos = SystemClock.elapsedRealtimeNanos();
+        } else {
+            timestampNanos = timestamp;
+        }
+        mDaemonHandler.post(() -> notifyInterfaceClassActivity(label, isActive,
+                timestampNanos, uid, false));
+    }
+
+    /**
+     * Notify our observers of a limit reached.
+     */
+    @Override
+    public void onQuotaLimitReached(String alertName, String ifName) throws RemoteException {
+        mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName));
+    }
+
+    /**
+     * Notify our observers of a limit reached.
+     */
+    public void notifyLimitReached(String limitName, String iface) {
+        invokeForAllObservers(o -> o.limitReached(limitName, iface));
+    }
+
+    @Override
+    public void onInterfaceDnsServerInfo(String ifName,
+            long lifetime, String[] servers) throws RemoteException {
+        mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers));
+    }
+
+    /**
+     * Notify our observers of DNS server information received.
+     */
+    public void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
+        invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses));
+    }
+
+    @Override
+    public void onInterfaceAddressUpdated(String addr,
+            String ifName, int flags, int scope) throws RemoteException {
+        final LinkAddress address = new LinkAddress(addr, flags, scope);
+        mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address));
+    }
+
+    /**
+     * Notify our observers of a new or updated interface address.
+     */
+    public void notifyAddressUpdated(String iface, LinkAddress address) {
+        invokeForAllObservers(o -> o.addressUpdated(iface, address));
+    }
+
+    @Override
+    public void onInterfaceAddressRemoved(String addr,
+            String ifName, int flags, int scope) throws RemoteException {
+        final LinkAddress address = new LinkAddress(addr, flags, scope);
+        mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address));
+    }
+
+    /**
+     * Notify our observers of a deleted interface address.
+     */
+    public void notifyAddressRemoved(String iface, LinkAddress address) {
+        invokeForAllObservers(o -> o.addressRemoved(iface, address));
+    }
+
+
+    @Override
+    public void onInterfaceAdded(String ifName) throws RemoteException {
+        mDaemonHandler.post(() -> notifyInterfaceAdded(ifName));
+    }
+
+    /**
+     * Notify our observers of an interface addition.
+     */
+    public void notifyInterfaceAdded(String iface) {
+        invokeForAllObservers(o -> o.interfaceAdded(iface));
+    }
+
+    @Override
+    public void onInterfaceRemoved(String ifName) throws RemoteException {
+        mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName));
+    }
+
+    /**
+     * Notify our observers of an interface removal.
+     */
+    public void notifyInterfaceRemoved(String iface) {
+        invokeForAllObservers(o -> o.interfaceRemoved(iface));
+    }
+
+    @Override
+    public void onInterfaceChanged(String ifName, boolean up) throws RemoteException {
+        mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up));
+    }
+
+    /**
+     * Notify our observers of an interface status change
+     */
+    public void notifyInterfaceStatusChanged(String iface, boolean up) {
+        invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up));
+    }
+
+    @Override
+    public void onInterfaceLinkStateChanged(String ifName, boolean up) throws RemoteException {
+        mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up));
+    }
+
+    /**
+     * Notify our observers of an interface link state change
+     * (typically, an Ethernet cable has been plugged-in or unplugged).
+     */
+    public void notifyInterfaceLinkStateChanged(String iface, boolean up) {
+        invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up));
+    }
+
+    @Override
+    public void onRouteChanged(boolean updated,
+            String route, String gateway, String ifName) throws RemoteException {
+        final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
+                ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
+                ifName);
+        mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
+    }
+
+    /**
+     * Notify our observers of a route change.
+     */
+    public void notifyRouteChange(boolean updated, RouteInfo route) {
+        if (updated) {
+            invokeForAllObservers(o -> o.routeUpdated(route));
+        } else {
+            invokeForAllObservers(o -> o.routeRemoved(route));
+        }
+    }
+
+    @Override
+    public void onStrictCleartextDetected(int uid, String hex) throws RemoteException {
+        // Don't do anything here because this is not a method of INetworkManagementEventObserver.
+        // Only the NMS subclass will implement this.
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index d91ce39..de7d77d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -158,7 +158,7 @@
             boolean detectShortcutTrigger) {
         MagnificationGestureHandler h = new MagnificationGestureHandler(
                 mContext, mMagnificationController,
-                detectTripleTap, detectShortcutTrigger);
+                detectTripleTap, detectShortcutTrigger, DISPLAY_0);
         mHandler = new TestHandler(h.mDetectingState, mClock) {
             @Override
             protected String messageToString(Message m) {
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index ac4a5fe..a3f36b7 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -24,11 +24,15 @@
 import static junit.framework.Assert.fail;
 
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.annotation.UserIdInt;
 import android.app.backup.BackupManager;
 import android.app.backup.IBackupManagerMonitor;
@@ -39,21 +43,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
-import android.test.mock.MockContentResolver;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.test.FakeSettingsProvider;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -99,10 +103,6 @@
     @Mock
     private Context mContextMock;
     @Mock
-    private File mSuppressFileMock;
-    @Mock
-    private File mSuppressFileParentMock;
-    @Mock
     private IBinder mAgentMock;
     @Mock
     private ParcelFileDescriptor mParcelFileDescriptorMock;
@@ -114,95 +114,53 @@
     private IBackupManagerMonitor mBackupManagerMonitorMock;
     @Mock
     private PrintWriter mPrintWriterMock;
+    @Mock
+    private UserManager mUserManagerMock;
+    @Mock
+    private UserInfo mUserInfoMock;
 
     private FileDescriptor mFileDescriptorStub = new FileDescriptor();
 
     private TrampolineTestable mTrampoline;
-    private MockContentResolver mContentResolver;
+    private File mTestDir;
+    private File mSuppressFile;
+    private File mActivatedFile;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mUserId = NON_USER_SYSTEM;
+        mUserId = UserHandle.USER_SYSTEM;
 
         SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
-        serviceUsers.append(UserHandle.SYSTEM.getIdentifier(), mUserBackupManagerService);
+        serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
         serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
         when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers);
 
+        when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
+        when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
+
         TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
         TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM;
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
         TrampolineTestable.sBackupDisabled = false;
+        TrampolineTestable.sUserManagerMock = mUserManagerMock;
 
-        when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock);
+        mTestDir = InstrumentationRegistry.getContext().getFilesDir();
+        mTestDir.mkdirs();
+
+        mSuppressFile = new File(mTestDir, "suppress");
+        TrampolineTestable.sSuppressFile = mSuppressFile;
+
+        mActivatedFile = new File(mTestDir, "activate-" + NON_USER_SYSTEM);
+        TrampolineTestable.sActivatedFiles.append(NON_USER_SYSTEM, mActivatedFile);
 
         mTrampoline = new TrampolineTestable(mContextMock);
-
-        mContentResolver = new MockContentResolver();
-        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-        when(mContextMock.getContentResolver()).thenReturn(mContentResolver);
     }
 
-    @Test
-    public void unlockUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(UserHandle.USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).startServiceForUser(UserHandle.USER_SYSTEM);
-    }
-
-    @Test
-    public void unlockUser_whenMultiUserSettingDisabled_isIgnoredForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock, never()).startServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void unlockUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).startServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(UserHandle.USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).stopServiceForUser(UserHandle.USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingDisabled_isIgnoredForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock, never()).stopServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
-
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).stopServiceForUser(NON_USER_SYSTEM);
+    @After
+    public void tearDown() throws Exception {
+        mSuppressFile.delete();
+        mActivatedFile.delete();
     }
 
     @Test
@@ -222,18 +180,6 @@
         assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
-    // Verify that BackupManagerService is not initialized if suppress file exists.
-    @Test
-    public void initializeService_suppressFileExists_nonInitialized() throws Exception {
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
-        trampoline.createBackupSuppressFileForUser(UserHandle.USER_SYSTEM);
-
-
-        trampoline.initializeService();
-
-        assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-    }
-
     @Test
     public void initializeService_doesNotStartServiceForUsers() {
         mTrampoline.initializeService();
@@ -247,15 +193,55 @@
     }
 
     @Test
-    public void isBackupServiceActive_forNonSysUser_whenSysUserIsDeactivated_returnsFalse() {
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+    public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
+        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
+            throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
         assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
-    public void setBackupServiceActive_callerSystemUid_serviceCreated() {
+    public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
+            throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        // Don't activate non-system user.
+
+        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void
+            isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
+                throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -264,7 +250,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_callerRootUid_serviceCreated() {
+    public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -273,7 +260,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_callerNonRootNonSystem_securityExceptionThrown() {
+    public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -281,14 +269,77 @@
             fail();
         } catch (SecurityException expected) {
         }
+    }
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.ROOT_UID;
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
+        doThrow(new SecurityException())
+                .when(mContextMock)
+                .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
+        mTrampoline.initializeService();
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
+        doThrow(new SecurityException())
+                .when(mContextMock)
+                .enforceCallingOrSelfPermission(
+                        eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
+        mTrampoline.initializeService();
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
     }
 
     @Test
     public void setBackupServiceActive_backupDisabled_ignored() {
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        trampoline.initializeService();
 
         trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
@@ -296,14 +347,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_nonUserSystem_ignored() {
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
-        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
-    }
-
-    @Test
     public void setBackupServiceActive_alreadyActive_ignored() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
         assertEquals(1, mTrampoline.getCreateServiceCallsCount());
@@ -315,6 +360,7 @@
 
     @Test
     public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
@@ -323,6 +369,7 @@
 
     @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -349,6 +396,21 @@
     }
 
     @Test
+    public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
+        mTrampoline.initializeService();
+        int otherUser = NON_USER_SYSTEM + 1;
+        File activateFile = new File(mTestDir, "activate-" + otherUser);
+        TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mTrampoline.isBackupServiceActive(otherUser));
+        activateFile.delete();
+    }
+
+    @Test
     public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.dataChanged(PACKAGE_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
@@ -1123,7 +1185,7 @@
     @Test
     public void requestBackup_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        when(mBackupManagerServiceMock.requestBackup(NON_USER_SYSTEM, PACKAGE_NAMES,
+        when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
         mTrampoline.initializeService();
 
@@ -1227,50 +1289,33 @@
         static int sCallingUserId = -1;
         static int sCallingUid = -1;
         static BackupManagerService sBackupManagerServiceMock = null;
+        static File sSuppressFile = null;
+        static SparseArray<File> sActivatedFiles = new SparseArray<>();
+        static UserManager sUserManagerMock = null;
         private int mCreateServiceCallsCount = 0;
-        private SparseArray<FakeFile> mSuppressFiles = new SparseArray<>();
-
-        private static class FakeFile extends File {
-            private boolean mExists;
-
-            FakeFile(String pathname) {
-                super(pathname);
-            }
-
-            @Override
-            public boolean exists() {
-                return mExists;
-            }
-
-            @Override
-            public boolean delete() {
-                mExists = false;
-                return true;
-            }
-
-            @Override
-            public boolean createNewFile() throws IOException {
-                mExists = true;
-                return true;
-            }
-        }
 
         TrampolineTestable(Context context) {
             super(context);
         }
 
         @Override
+        protected UserManager getUserManager() {
+            return sUserManagerMock;
+        }
+
+        @Override
         public boolean isBackupDisabled() {
             return sBackupDisabled;
         }
 
         @Override
-        public File getSuppressFileForUser(int userId) {
-            if (mSuppressFiles.get(userId) == null) {
-                FakeFile file = new FakeFile(Integer.toString(userId));
-                mSuppressFiles.append(userId, file);
-            }
-            return mSuppressFiles.get(userId);
+        protected File getSuppressFileForSystemUser() {
+            return sSuppressFile;
+        }
+
+        @Override
+        protected File getActivatedFileForNonSystemUser(int userId) {
+            return sActivatedFiles.get(userId);
         }
 
         protected int binderGetCallingUserId() {
@@ -1289,11 +1334,6 @@
         }
 
         @Override
-        protected void createBackupSuppressFileForUser(int userId) throws IOException {
-            getSuppressFileForUser(userId).createNewFile();
-        }
-
-        @Override
         protected void postToHandler(Runnable runnable) {
             runnable.run();
         }
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index ca39a7f..0b01657 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -918,15 +918,14 @@
         }
 
         setAccessibilityColorInversion(true);
-        setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
 
         startService();
-        assertAccessibilityTransformActivated(true /* activated */ );
-        assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+        assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
+        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
         }
     }
 
@@ -937,15 +936,14 @@
         }
 
         setAccessibilityColorCorrection(true);
-        setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
 
         startService();
-        assertAccessibilityTransformActivated(true /* activated */ );
-        assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+        assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
+        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
         }
     }
 
@@ -957,15 +955,14 @@
 
         setAccessibilityColorCorrection(true);
         setAccessibilityColorInversion(true);
-        setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
 
         startService();
-        assertAccessibilityTransformActivated(true /* activated */ );
-        assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
-        if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
-        } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
-            assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+        assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        if (isColorModeValid(ColorDisplayManager.COLOR_MODE_SATURATED)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
+        } else if (isColorModeValid(ColorDisplayManager.COLOR_MODE_AUTOMATIC)) {
+            assertActiveColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
         }
     }
 
@@ -977,12 +974,11 @@
 
         setAccessibilityColorCorrection(false);
         setAccessibilityColorInversion(false);
-        setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
 
         startService();
-        assertAccessibilityTransformActivated(false /* activated */ );
-        assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
-        assertActiveColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+        assertUserColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        assertActiveColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
     }
 
     /**
@@ -1098,17 +1094,6 @@
     }
 
     /**
-     * Convenience method for asserting that Accessibility color transform is detected.
-     *
-     * @param state {@code true} if any Accessibility transform should be activated
-     */
-    private void assertAccessibilityTransformActivated(boolean state) {
-        assertWithMessage("Unexpected Accessibility color transform state")
-                .that(mColorDisplayController.getAccessibilityTransformActivated())
-                .isEqualTo(state);
-    }
-
-    /**
      * Convenience method for asserting that the active color mode matches expectation.
      *
      * @param mode the expected active color mode.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 5656289..056568a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -598,6 +598,10 @@
                 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                 false, false, false);
+        runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
+                Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_callingUidHasVisibleWindow_notAborted", false,
                 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
new file mode 100644
index 0000000..19ace3c
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.os.IBinder;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationTarget;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for change transitions
+ *
+ * Build/Install/Run:
+ *  atest WmTests:AppChangeTransitionTests
+ */
+@FlakyTest(detail = "Promote when shown to be stable.")
+@SmallTest
+public class AppChangeTransitionTests extends WindowTestsBase {
+
+    private TaskStack mStack;
+    private Task mTask;
+    private WindowTestUtils.TestAppWindowToken mToken;
+
+    @Before
+    public void setUp() throws Exception {
+        mStack = createTaskStackOnDisplay(mDisplayContent);
+        mTask = createTaskInStack(mStack, 0 /* userId */);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+        mToken.mSkipOnParentSet = false;
+
+        mTask.addChild(mToken, 0);
+    }
+
+    class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
+        @Override
+        public void onAnimationStart(RemoteAnimationTarget[] apps,
+                IRemoteAnimationFinishedCallback finishedCallback) {
+            for (RemoteAnimationTarget target : apps) {
+                assertNotNull(target.startBounds);
+            }
+            try {
+                finishedCallback.onAnimationFinished();
+            } catch (Exception e) {
+                throw new RuntimeException("Something went wrong");
+            }
+        }
+
+        @Override
+        public void onAnimationCancelled() {
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testModeChangeRemoteAnimatorNoSnapshot() {
+        RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+        RemoteAnimationAdapter adapter =
+                new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
+        definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
+        mDisplayContent.registerRemoteAnimations(definition);
+
+        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        assertEquals(1, mDisplayContent.mChangingApps.size());
+        assertNull(mToken.getThumbnail());
+
+        waitUntilHandlersIdle();
+        mToken.removeImmediately();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 3740786..a498a1a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -94,9 +94,9 @@
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
         topBar.getFrameLw().set(0, 0, 500, 100);
         mProvider.setWindow(topBar, null);
-        mProvider.updateControlForTarget(target);
+        mProvider.updateControlForTarget(target, false /* force */);
         assertNotNull(mProvider.getControl());
-        mProvider.updateControlForTarget(null);
+        mProvider.updateControlForTarget(null, false /* force */);
         assertNull(mProvider.getControl());
     }
 
@@ -106,7 +106,7 @@
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
         topBar.getFrameLw().set(0, 0, 500, 100);
         mProvider.setWindow(topBar, null);
-        mProvider.updateControlForTarget(target);
+        mProvider.updateControlForTarget(target, false /* force */);
         InsetsState state = new InsetsState();
         state.getSource(TYPE_TOP_BAR).setVisible(false);
         mProvider.onInsetsModified(target, state.getSource(TYPE_TOP_BAR));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 9478be9..b867799 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -77,7 +77,7 @@
         MockitoAnnotations.initMocks(this);
 
         when(mMockRunner.asBinder()).thenReturn(new Binder());
-        mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
+        mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
         mAdapter.setCallingPid(123);
         mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
new file mode 100644
index 0000000..a7c84a1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.content.pm.ApplicationInfo;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+/**
+ * Tests for the {@link WindowProcessController} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:WindowProcessControllerTests
+ */
+@Presubmit
+public class WindowProcessControllerTests extends ActivityTestsBase {
+
+    @Test
+    public void testDisplayConfigurationListener() {
+        final WindowProcessController wpc = new WindowProcessController(
+                        mService, mock(ApplicationInfo.class), null, 0, -1, null, null);
+        //By default, the process should not listen to any display.
+        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+
+        // Register to display 1 as a listener.
+        TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
+        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertTrue(testActivityDisplay1.containsListener(wpc));
+        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+
+        // Move to display 2.
+        TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
+        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
+        assertFalse(testActivityDisplay1.containsListener(wpc));
+        assertTrue(testActivityDisplay2.containsListener(wpc));
+        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+
+        // Null ActivityDisplay will not change anything.
+        wpc.registerDisplayConfigurationListenerLocked(null);
+        assertTrue(testActivityDisplay2.containsListener(wpc));
+        assertEquals(testActivityDisplay2.mDisplayId, wpc.getDisplayId());
+
+        // Unregister listener will remove the wpc from registered displays.
+        wpc.unregisterDisplayConfigurationListenerLocked();
+        assertFalse(testActivityDisplay1.containsListener(wpc));
+        assertFalse(testActivityDisplay2.containsListener(wpc));
+        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+
+        // Unregistration still work even if the display was removed.
+        wpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
+        assertEquals(testActivityDisplay1.mDisplayId, wpc.getDisplayId());
+        mRootActivityContainer.removeChild(testActivityDisplay1);
+        wpc.unregisterDisplayConfigurationListenerLocked();
+        assertEquals(INVALID_DISPLAY, wpc.getDisplayId());
+    }
+
+    private TestActivityDisplay createTestActivityDisplayInContainer() {
+        final TestActivityDisplay testActivityDisplay = createNewActivityDisplay();
+        mRootActivityContainer.addChild(testActivityDisplay, POSITION_TOP);
+        return testActivityDisplay;
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 44e998b..2263cf3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -152,6 +152,7 @@
     public static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
         private Transaction mPendingTransactionOverride;
+        boolean mSkipOnParentSet = true;
 
         private TestAppWindowToken(DisplayContent dc) {
             super(dc.mWmService, new IApplicationToken.Stub() {
@@ -200,7 +201,9 @@
 
         @Override
         void onParentSet() {
-            // Do nothing.
+            if (!mSkipOnParentSet) {
+                super.onParentSet();
+            }
         }
 
         @Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bb01f04..718f2d3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -17,13 +17,18 @@
 package com.android.server.voiceinteraction;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -78,6 +83,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * SystemService that publishes an IVoiceInteractionManagerService.
@@ -200,6 +206,7 @@
 
         VoiceInteractionManagerServiceStub() {
             mEnableService = shouldEnableService(mContext);
+            new RoleObserver(mContext.getMainExecutor());
         }
 
         // TODO: VI Make sure the caller is the current user or profile
@@ -1268,6 +1275,106 @@
                     getActiveServiceComponentName());
         }
 
+        class RoleObserver implements OnRoleHoldersChangedListener {
+            private PackageManager mPm = mContext.getPackageManager();
+            private RoleManager mRm = mContext.getSystemService(RoleManager.class);
+
+            RoleObserver(@NonNull @CallbackExecutor Executor executor) {
+                mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
+            }
+
+            private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
+                ResolveInfo resolveInfo = mPm.resolveServiceAsUser(
+                        new Intent(RecognitionService.SERVICE_INTERFACE),
+                        PackageManager.GET_META_DATA, user.getIdentifier());
+
+                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+                    Log.w(TAG, "Unable to resolve default voice recognition service.");
+                    return "";
+                }
+
+                return new ComponentName(resolveInfo.serviceInfo.packageName,
+                        resolveInfo.serviceInfo.name).flattenToShortString();
+            }
+
+            /**
+             * Convert the assistant-role holder into settings. The rest of the system uses the
+             * settings.
+             *
+             * @param roleName the name of the role whose holders are changed
+             * @param user the user for this role holder change
+             */
+            @Override
+            public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+                if (!roleName.equals(RoleManager.ROLE_ASSISTANT)) {
+                    return;
+                }
+
+                List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
+
+                if (roleHolders.isEmpty()) {
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.ASSISTANT, "");
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user));
+                } else {
+                    // Assistant is singleton role
+                    String pkg = roleHolders.get(0);
+
+                    // Try to set role holder as VoiceInteractionService
+                    List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
+                            new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
+                            PackageManager.GET_META_DATA, user.getIdentifier());
+
+                    for (ResolveInfo resolveInfo : services) {
+                        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+                        VoiceInteractionServiceInfo voiceInteractionServiceInfo =
+                                new VoiceInteractionServiceInfo(mPm, serviceInfo);
+                        if (!voiceInteractionServiceInfo.getSupportsAssist()) {
+                            continue;
+                        }
+
+                        String serviceComponentName = serviceInfo.getComponentName()
+                                .flattenToShortString();
+
+                        String serviceRecognizerName = new ComponentName(pkg,
+                                voiceInteractionServiceInfo.getRecognitionService())
+                                .flattenToShortString();
+
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.ASSISTANT, serviceComponentName);
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
+
+                        return;
+                    }
+
+                    // If no service could be found try to set assist activity
+                    final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
+                            new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
+                            PackageManager.MATCH_DEFAULT_ONLY, user.getIdentifier());
+
+                    for (ResolveInfo resolveInfo : activities) {
+                        ActivityInfo activityInfo = resolveInfo.activityInfo;
+
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.ASSISTANT,
+                                activityInfo.getComponentName().flattenToShortString());
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_RECOGNITION_SERVICE,
+                                getDefaultRecognizer(user));
+                    }
+                }
+            }
+        }
+
         class SettingsObserver extends ContentObserver {
             SettingsObserver(Handler handler) {
                 super(handler);
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 2b99ce1..2d29875 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -50,10 +50,10 @@
     }
 
     private CallAttributes(Parcel in) {
-        mPreciseCallState = (PreciseCallState) in.readValue(mPreciseCallState.getClass()
-                .getClassLoader());
+        mPreciseCallState = (PreciseCallState)
+                in.readValue(PreciseCallState.class.getClassLoader());
         mNetworkType = in.readInt();
-        mCallQuality = (CallQuality) in.readValue(mCallQuality.getClass().getClassLoader());
+        mCallQuality = (CallQuality) in.readValue(CallQuality.class.getClassLoader());
     }
 
     // getters
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a33b44c..349880d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -608,11 +608,41 @@
     public static final String KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL =
             "carrier_promote_wfc_on_call_fail_bool";
 
-    /** Flag specifying whether provisioning is required for VOLTE. */
+    /**
+     * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi
+     * Calling.
+     */
     public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
             = "carrier_volte_provisioning_required_bool";
 
     /**
+     * Flag indicating whether or not the IMS MmTel UT capability requires carrier provisioning
+     * before it can be set as enabled.
+     *
+     * If true, the UT capability will be set to false for the newly loaded subscription
+     * and will require the carrier provisioning app to set the persistent provisioning result.
+     * If false, the platform will not wait for provisioning status updates for the UT capability
+     * and enable the UT over IMS capability for the subscription when the subscription is loaded.
+     *
+     * The default value for this key is {@code false}.
+     */
+    public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL =
+            "carrier_ut_provisioning_required_bool";
+
+    /**
+     * Flag indicating whether or not the carrier supports Supplementary Services over the UT
+     * interface for this subscription.
+     *
+     * If true, the device will use Supplementary Services over UT when provisioned (see
+     * {@link #KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL}). If false, this device will fallback to
+     * circuit switch for supplementary services and will disable this capability for IMS entirely.
+     *
+     * The default value for this key is {@code true}.
+     */
+    public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL =
+            "carrier_supports_ss_over_ut_bool";
+
+    /**
      * Flag specifying if WFC provisioning depends on VoLTE provisioning.
      *
      * {@code false}: default value; honor actual WFC provisioning state.
@@ -2575,6 +2605,8 @@
         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 0fa1b41..bca088e 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -91,20 +91,6 @@
             "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
 
     /**
-     * Intent action to select a profile to enable before download a new eSIM profile.
-     *
-     * May be called during device provisioning when there are multiple slots having profiles on
-     * them. This Intent launches a screen for all the current existing profiles and let users to
-     * choose which one they want to enable. In this case, the slot contains the profile will be
-     * activated.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final String ACTION_PROFILE_SELECTION =
-            "android.telephony.euicc.action.PROFILE_SELECTION";
-
-    /**
      * Intent action to provision an embedded subscription.
      *
      * <p>May be called during device provisioning to launch a screen to perform embedded SIM
@@ -325,8 +311,8 @@
     @IntDef(prefix = {"EUICC_ACTIVATION_"}, value = {
             EUICC_ACTIVATION_TYPE_DEFAULT,
             EUICC_ACTIVATION_TYPE_BACKUP,
-            EUICC_ACTIVATION_TYPE_TRANSFER
-
+            EUICC_ACTIVATION_TYPE_TRANSFER,
+            EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED,
     })
     public @interface EuiccActivationType{}
 
@@ -360,6 +346,14 @@
     @SystemApi
     public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3;
 
+    /**
+     * The activation flow of eSIM requiring user account will be started. This can only be used
+     * when there is user account signed in. Otherwise, the flow will be failed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED = 4;
 
     /**
      * Euicc OTA update status which can be got by {@link #getOtaStatus}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 9414abd..5b2e635 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -86,9 +86,7 @@
 
     /**
      * Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
-     * @hide
      */
-    @SystemApi
     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
 
     /**
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index d37198a..086a765 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -21,13 +21,17 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
 import android.content.Context;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsConfigCallback;
+import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 
 import com.android.internal.telephony.ITelephony;
 
@@ -38,13 +42,68 @@
  * to changes in these configurations.
  *
  * Note: IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
- * applications and may vary.
+ * applications and may vary. For compatibility purposes, the first 100 integer values used in
+ * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys
+ * previously defined in the Android framework. Some common constants have been defined in this
+ * class to make integrating with other system apps easier. USE WITH CARE!
+ *
+ * To avoid collisions, please use String based configurations when possible:
+ * {@link #setProvisioningStringValue(int, String)} and {@link #getProvisioningStringValue(int)}.
  * @hide
  */
 @SystemApi
 public class ProvisioningManager {
 
     /**
+     * The query from {@link #getProvisioningStringValue(int)} has resulted in an unspecified error.
+     */
+    public static final String STRING_QUERY_RESULT_ERROR_GENERIC =
+            "STRING_QUERY_RESULT_ERROR_GENERIC";
+
+    /**
+     * The query from {@link #getProvisioningStringValue(int)} has resulted in an error because the
+     * ImsService implementation was not ready for provisioning queries.
+     */
+    public static final String STRING_QUERY_RESULT_ERROR_NOT_READY =
+            "STRING_QUERY_RESULT_ERROR_NOT_READY";
+
+    /**
+     * The integer result of provisioning for the queried key is disabled.
+     */
+    public static final int PROVISIONING_VALUE_DISABLED = 0;
+
+    /**
+     * The integer result of provisioning for the queried key is enabled.
+     */
+    public static final int PROVISIONING_VALUE_ENABLED = 1;
+
+
+    /**
+     * Override the user-defined WiFi Roaming enabled setting for this subscription, defined in
+     * {@link SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, for the purposes of provisioning
+     * the subscription for WiFi Calling.
+     *
+     * @see #getProvisioningIntValue(int)
+     * @see #setProvisioningIntValue(int, int)
+     */
+    public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26;
+
+    /**
+     * Override the user-defined WiFi mode for this subscription, defined in
+     * {@link SubscriptionManager#WFC_MODE_CONTENT_URI}, for the purposes of provisioning
+     * this subscription for WiFi Calling.
+     *
+     * Valid values for this key are:
+     * {@link ImsMmTelManager#WIFI_MODE_WIFI_ONLY},
+     * {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, or
+     * {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}.
+     *
+     * @see #getProvisioningIntValue(int)
+     * @see #setProvisioningIntValue(int, int)
+     */
+    public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27;
+
+    /**
      * Callback for IMS provisioning changes.
      */
     public static class Callback {
@@ -180,10 +239,15 @@
 
     /**
      * Query for the integer value associated with the provided key.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
      * @param key An integer that represents the provisioning key, which is defined by the OEM.
-     * @return an integer value for the provided key.
+     * @return an integer value for the provided key, or
+     * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist.
      * @throws IllegalArgumentException if the key provided was invalid.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public int getProvisioningIntValue(int key) {
         try {
@@ -195,10 +259,16 @@
 
     /**
      * Query for the String value associated with the provided key.
-     * @param key An integer that represents the provisioning key, which is defined by the OEM.
-     * @return a String value for the provided key, or {@code null} if the key doesn't exist.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * @param key A String that represents the provisioning key, which is defined by the OEM.
+     * @return a String value for the provided key, {@code null} if the key doesn't exist, or one
+     * of the following error codes: {@link #STRING_QUERY_RESULT_ERROR_GENERIC},
+     * {@link #STRING_QUERY_RESULT_ERROR_NOT_READY}.
      * @throws IllegalArgumentException if the key provided was invalid.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getProvisioningStringValue(int key) {
         try {
@@ -210,10 +280,16 @@
 
     /**
      * Set the integer value associated with the provided key.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * Use {@link #setProvisioningStringValue(int, String)} with proper namespacing (to be defined
+     * per OEM or carrier) when possible instead to avoid key collision if needed.
      * @param key An integer that represents the provisioning key, which is defined by the OEM.
      * @param value a integer value for the provided key.
      * @return the result of setting the configuration value.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public @ImsConfigImplBase.SetConfigResult int setProvisioningIntValue(int key, int value) {
         try {
@@ -226,10 +302,14 @@
     /**
      * Set the String value associated with the provided key.
      *
-     * @param key An integer that represents the provisioning key, which is defined by the OEM.
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * @param key A String that represents the provisioning key, which is defined by the OEM and
+     *     should be appropriately namespaced to avoid collision.
      * @param value a String value for the provided key.
      * @return the result of setting the configuration value.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public @ImsConfigImplBase.SetConfigResult int setProvisioningStringValue(int key,
             String value) {
@@ -240,6 +320,55 @@
         }
     }
 
+    /**
+     * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+     *
+     * Provisioning may or may not be required, depending on the carrier configuration. If
+     * provisioning is not required for the carrier associated with this subscription or the device
+     * does not support the capability/technology combination specified, this operation will be a
+     * no-op.
+     *
+     * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+     * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+     * @param isProvisioned true if the device is provisioned for UT over IMS, false otherwise.
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void setProvisioningStatusForCapability(
+            @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int tech,  boolean isProvisioned) {
+        try {
+            getITelephony().setImsProvisioningStatusForCapability(mSubId, capability, tech,
+                    isProvisioned);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Get the provisioning status for the IMS MmTel capability specified.
+     *
+     * If provisioning is not required for the queried
+     * {@link MmTelFeature.MmTelCapabilities.MmTelCapability} and
+     * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will
+     * always return {@code true}.
+     *
+     * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+     * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+     * @return true if the device is provisioned for the capability or does not require
+     * provisioning, false if the capability does require provisioning and has not been
+     * provisioned yet.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean getProvisioningStatusForCapability(
+            @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int tech) {
+        try {
+            return getITelephony().getImsProvisioningStatusForCapability(mSubId, capability, tech);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     private static SubscriptionManager getSubscriptionManager(Context context) {
         SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
         if (manager == null) {
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 7c793a5..1ee8563 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -97,6 +97,13 @@
         public @ImsRegistrationImplBase.ImsRegistrationTech int getRadioTech() {
             return radioTech;
         }
+
+        @Override
+        public String toString() {
+            return "CapabilityPair{"
+                    + "mCapability=" + mCapability
+                    + ", radioTech=" + radioTech + '}';
+        }
     }
 
     // Pair contains <radio tech, mCapability>
@@ -212,6 +219,13 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "CapabilityChangeRequest{"
+                + "mCapabilitiesToEnable=" + mCapabilitiesToEnable
+                + ", mCapabilitiesToDisable=" + mCapabilitiesToDisable + '}';
+    }
+
     /**
      * @hide
      */
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 71a2174..4fc6a19 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -277,12 +277,14 @@
          * Wi-Fi calling roaming status.
          * Value is in Integer format. ON (1), OFF(0).
          */
-        public static final int VOICE_OVER_WIFI_ROAMING = 26;
+        public static final int VOICE_OVER_WIFI_ROAMING =
+                ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE;
         /**
          * Wi-Fi calling modem - WfcModeFeatureValueConstants.
          * Value is in Integer format.
          */
-        public static final int VOICE_OVER_WIFI_MODE = 27;
+        public static final int VOICE_OVER_WIFI_MODE =
+                ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE;
         /**
          * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
          * Value is in Integer format.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9cc173c..8237d39 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1765,6 +1765,24 @@
     void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback);
 
     /**
+     * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+     */
+    void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
+            boolean isProvisioned);
+
+    /**
+     * Get the provisioning status for the IMS MmTel capability specified.
+     */
+    boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech);
+
+    /** Is the capability and tech flagged as provisioned in the cache */
+    boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech);
+
+    /** Set the provisioning for the capability and tech in the cache */
+    void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech,
+            boolean isProvisioned);
+
+    /**
      * Return an integer containing the provisioning value for the specified provisioning key.
      */
     int getImsProvisioningInt(int subId, int key);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 0edc002..c76d153 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -284,10 +284,6 @@
      */
     private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
             int uid, String callingPackage, String message) {
-        // If the device identifier check is enabled then enforce the new access requirements for
-        // both 1P and 3P apps.
-        boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 1;
         // Check if the application is a 3P app; if so then a separate setting is required to relax
         // the check to begin flagging problems with 3P apps early.
         boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
@@ -300,6 +296,11 @@
                 context.getContentResolver(),
                 Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED, 0) == 1;
         boolean isNonPrivApp = false;
+        // Similar to above support relaxing the check for privileged apps while still enforcing it
+        // for non-privileged and 3P apps.
+        boolean relaxPrivDeviceIdentifierCheck = Settings.Global.getInt(
+                context.getContentResolver(),
+                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
         ApplicationInfo callingPackageInfo = null;
         try {
             callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
@@ -315,37 +316,28 @@
             Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
                     e);
         }
-        Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
-                + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp);
-        // The new Q restrictions for device identifier access will be enforced if any of the
-        // following are true:
-        // - The PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED setting has been set.
-        // - The app requesting a device identifier is not a preloaded app (3P), and the
-        //   PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED setting has not been set.
-        // - The app requesting a device identifier is a preloaded app but is not a privileged app,
-        //   and the PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED setting has not been set.
-        if (enableDeviceIdentifierCheck
+        // The new Q restrictions for device identifier access will be enforced for all apps with
+        // settings to individually disable the new restrictions for privileged, preloaded
+        // non-privileged, and 3P apps.
+        if ((!is3PApp && !isNonPrivApp && !relaxPrivDeviceIdentifierCheck)
                 || (is3PApp && !relax3PDeviceIdentifierCheck)
                 || (isNonPrivApp && !relaxNonPrivDeviceIdentifierCheck)) {
-            boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
-            if (callingPackage != null) {
-                // if the target SDK is pre-Q or the target Q behavior is disabled then check if
-                // the calling package would have previously had access to device identifiers.
-                if (callingPackageInfo != null && (
-                        callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
-                                || targetQBehaviorDisabled)) {
-                    if (context.checkPermission(
-                            android.Manifest.permission.READ_PHONE_STATE,
-                            pid,
-                            uid) == PackageManager.PERMISSION_GRANTED) {
-                        return false;
-                    }
-                    if (SubscriptionManager.isValidSubscriptionId(subId)
-                            && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
-                            == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                        return false;
-                    }
+            Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
+                    + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp);
+            // if the target SDK is pre-Q then check if the calling package would have previously
+            // had access to device identifiers.
+            if (callingPackageInfo != null && (
+                    callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+                if (context.checkPermission(
+                        android.Manifest.permission.READ_PHONE_STATE,
+                        pid,
+                        uid) == PackageManager.PERMISSION_GRANTED) {
+                    return false;
+                }
+                if (SubscriptionManager.isValidSubscriptionId(subId)
+                        && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                    return false;
                 }
             }
             throw new SecurityException(message + ": The user " + uid
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 34aa258..780bb24 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -36,6 +36,17 @@
 include $(BUILD_PACKAGE)
 ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)
 
+# RollbackTestAppACrashingV2.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/ACrashingV2.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppACrashingV2
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_A_CRASHING_V2 := $(LOCAL_INSTALLED_MODULE)
+
 # RollbackTestAppBv1.apk
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
@@ -68,6 +79,7 @@
 LOCAL_JAVA_RESOURCE_FILES := \
   $(ROLLBACK_TEST_APP_AV1) \
   $(ROLLBACK_TEST_APP_AV2) \
+  $(ROLLBACK_TEST_APP_A_CRASHING_V2) \
   $(ROLLBACK_TEST_APP_BV1) \
   $(ROLLBACK_TEST_APP_BV2)
 LOCAL_SDK_VERSION := system_current
@@ -77,5 +89,6 @@
 # Clean up local variables
 ROLLBACK_TEST_APP_AV1 :=
 ROLLBACK_TEST_APP_AV2 :=
+ROLLBACK_TEST_APP_A_CRASHING_V2 :=
 ROLLBACK_TEST_APP_BV1 :=
 ROLLBACK_TEST_APP_BV2 :=
diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml
new file mode 100644
index 0000000..5708d23
--- /dev/null
+++ b/tests/RollbackTest/TestApp/ACrashingV2.xml
@@ -0,0 +1,37 @@
+<?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.tests.rollback.testapp.A"
+    android:versionCode="2"
+    android:versionName="2.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App A v2">
+        <meta-data android:name="version" android:value="2" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
+            <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.DEFAULT"/>
+              <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
new file mode 100644
index 0000000..02a439b
--- /dev/null
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A crashing test app for testing apk rollback support.
+ */
+public class CrashingMainActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        throw new RuntimeException("Intended force crash");
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 9d67cea..13ac4f0 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -38,6 +38,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -57,6 +58,7 @@
 
     private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
     private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
+    private static final String INSTRUMENTED_APP = "com.android.tests.rollback";
 
     /**
      * Test basic rollbacks.
@@ -663,4 +665,63 @@
         assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
         assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
     }
+
+    // TODO(zezeozue): Stop ignoring after fixing race between rolling back and testing version
+    /**
+     * Test bad update automatic rollback.
+     */
+    @Ignore("Flaky")
+    @Test
+    public void testBadUpdateRollback() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            // Prep installation of the test apps.
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // Both test apps should now be available for rollback, and the
+            // targetPackage returned for rollback should be correct.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+
+            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+
+            // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
+            for (int i = 0; i < 5; i++) {
+                RollbackTestUtils.launchPackage(TEST_APP_A);
+                Thread.sleep(1000);
+            }
+            Thread.sleep(1000);
+
+            // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // Instrumented app is still the package installer
+            Context context = InstrumentationRegistry.getContext();
+            String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A);
+            assertEquals(INSTRUMENTED_APP, installer);
+            // TEST_APP_B is untouched
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index fbc3d8f..edb1355 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -135,6 +135,17 @@
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
+    /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
+    static void launchPackage(String packageName)
+            throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setPackage(packageName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        context.startActivity(intent);
+    }
+
     /**
      * Installs the apks with the given resource names as an atomic set.
      *
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 5b17224..0b74d87 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -246,17 +246,17 @@
         assertFalse(vpn.getLockdown());
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
         assertTrue(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
         assertTrue(vpn.getAlwaysOn());
         assertTrue(vpn.getLockdown());
 
         // Remove always-on configuration.
-        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
+        assertTrue(vpn.setAlwaysOnPackage(null, false));
         assertFalse(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
     }
@@ -270,11 +270,11 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -283,7 +283,7 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[1]);
 
         // Switch to another app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
         verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -297,87 +297,6 @@
     }
 
     @Test
-    public void testLockdownWhitelist() throws Exception {
-        final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = UidRange.createForUser(primaryUser.id);
-
-        // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
-        }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-
-        // Change whitelisted app to PKGS[3].
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
-        }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
-                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
-        }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
-
-        // Change the VPN app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
-        }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
-        }));
-        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
-
-        // Remove the whitelist.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
-                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
-        }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
-        }));
-        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
-                user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0]);
-
-        // Add the whitelist.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
-        }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
-        }));
-        assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
-
-        // Try whitelisting a package with a comma, should be rejected.
-        assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
-
-        // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
-        // Whitelisted package should change from PGKS[1] to PKGS[2].
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
-                Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
-                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
-        }));
-        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
-                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
-                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
-        }));
-    }
-
-    @Test
     public void testLockdownAddingAProfile() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
@@ -391,7 +310,7 @@
         final UidRange profile = UidRange.createForUser(tempProfile.id);
 
         // Set lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
             new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -517,7 +436,7 @@
                 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
 
         // Start showing a notification for disconnected once always-on.
-        vpn.setAlwaysOnPackage(PKGS[0], false, null);
+        vpn.setAlwaysOnPackage(PKGS[0], false);
         order.verify(mNotificationManager)
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
@@ -531,7 +450,7 @@
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
         // Notification should be cleared after unsetting always-on package.
-        vpn.setAlwaysOnPackage(null, false, null);
+        vpn.setAlwaysOnPackage(null, false);
         order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
     }
 
@@ -664,9 +583,7 @@
             doAnswer(invocation -> {
                 final String appName = (String) invocation.getArguments()[0];
                 final int userId = (int) invocation.getArguments()[1];
-                Integer appId = packages.get(appName);
-                if (appId == null) throw new PackageManager.NameNotFoundException(appName);
-                return UserHandle.getUid(userId, appId);
+                return UserHandle.getUid(userId, packages.get(appName));
             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
         } catch (Exception e) {
         }
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
index f2ecef9..e57433a 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -202,9 +202,11 @@
         final CountDownLatch latch = new CountDownLatch(1);
         functor.accept(latch);
         try {
-            latch.await(5000, TimeUnit.MILLISECONDS);
+            if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+                fail(timeoutMessage);
+            }
         } catch (InterruptedException e) {
-            fail(timeoutMessage);
+            fail("Thread was interrupted");
         }
     }
 
@@ -314,6 +316,7 @@
                             assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
                             assertNull(key);
                             assertNull(attr);
+                            latch.countDown();
                         })));
     }
 
@@ -383,6 +386,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[5], key);
+                    latch.countDown();
                 })));
 
         // MTU matches key 4 but v4 address matches key 5. The latter is stronger.
@@ -392,6 +396,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[5], key);
+                    latch.countDown();
                 })));
 
         // Closest to key 3 (indeed, identical)
@@ -402,6 +407,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[3], key);
+                    latch.countDown();
                 })));
 
         // Group hint alone must not be strong enough to override the rest
@@ -411,6 +417,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[3], key);
+                    latch.countDown();
                 })));
 
         // Still closest to key 3, though confidence is lower
@@ -421,6 +428,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[3], key);
+                    latch.countDown();
                 })));
 
         // But changing the MTU makes this closer to key 4
@@ -430,6 +438,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(FAKE_KEYS[4], key);
+                    latch.countDown();
                 })));
 
         // MTU alone not strong enough to make this group-close
@@ -441,6 +450,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertNull(key);
+                    latch.countDown();
                 })));
     }
 
@@ -450,6 +460,7 @@
                     assertTrue("Retrieve network sameness not successful : " + status.resultCode,
                             status.isSuccess());
                     assertEquals(sameness, answer.getNetworkSameness());
+                    latch.countDown();
                 })));
     }
 
@@ -488,6 +499,7 @@
                             + status.resultCode, status.isSuccess());
                     assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
                     assertNull(answer);
+                    latch.countDown();
                 })));
     }
 }
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 9b5df56..06ff05e 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -1,6 +1,8 @@
-java_library_host {
+java_plugin {
     name: "view-inspector-annotation-processor",
 
+    processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+
     srcs: ["src/java/**/*.java"],
     java_resource_dirs: ["src/resources"],
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index d2d711f..96493de 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -787,6 +787,18 @@
     public boolean trusted;
 
     /**
+     * This Wifi configuration is created from a {@link WifiNetworkSuggestion}
+     * @hide
+     */
+    public boolean fromWifiNetworkSuggestion;
+
+    /**
+     * This Wifi configuration is created from a {@link WifiNetworkSpecifier}
+     * @hide
+     */
+    public boolean fromWifiNetworkSpecifier;
+
+    /**
      * Indicates if the creator of this configuration has expressed that it
      * should be considered metered.
      *
@@ -1668,6 +1680,8 @@
         ephemeral = false;
         osu = false;
         trusted = true; // Networks are considered trusted by default.
+        fromWifiNetworkSuggestion = false;
+        fromWifiNetworkSpecifier = false;
         meteredHint = false;
         meteredOverride = METERED_OVERRIDE_NONE;
         useExternalScores = false;
@@ -1779,10 +1793,13 @@
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.osu) sbuf.append(" osu");
         if (this.trusted) sbuf.append(" trusted");
+        if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion");
+        if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
         if (this.meteredHint) sbuf.append(" meteredHint");
         if (this.useExternalScores) sbuf.append(" useExternalScores");
         if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
-                || this.ephemeral || this.trusted || this.meteredHint || this.useExternalScores) {
+                || this.ephemeral || this.trusted || this.fromWifiNetworkSuggestion
+                || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) {
             sbuf.append("\n");
         }
         if (this.meteredOverride != METERED_OVERRIDE_NONE) {
@@ -2270,6 +2287,8 @@
             ephemeral = source.ephemeral;
             osu = source.osu;
             trusted = source.trusted;
+            fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion;
+            fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier;
             meteredHint = source.meteredHint;
             meteredOverride = source.meteredOverride;
             useExternalScores = source.useExternalScores;
@@ -2347,6 +2366,8 @@
         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(trusted ? 1 : 0);
+        dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0);
+        dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0);
         dest.writeInt(meteredHint ? 1 : 0);
         dest.writeInt(meteredOverride);
         dest.writeInt(useExternalScores ? 1 : 0);
@@ -2418,6 +2439,8 @@
                 config.isLegacyPasspointConfig = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
                 config.trusted = in.readInt() != 0;
+                config.fromWifiNetworkSuggestion =  in.readInt() != 0;
+                config.fromWifiNetworkSpecifier =  in.readInt() != 0;
                 config.meteredHint = in.readInt() != 0;
                 config.meteredOverride = in.readInt();
                 config.useExternalScores = in.readInt() != 0;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 40077e1..8086039 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -16,7 +16,7 @@
 
 package android.net.wifi;
 
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 import static android.Manifest.permission.ACCESS_WIFI_STATE;
 import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
 
@@ -950,8 +950,7 @@
      * which was created with {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} flag
      * set.
      * <p>
-     * Note: The broadcast is sent to the app only if it holds either one of
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * Note: The broadcast is sent to the app only if it holds
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
      *
      * @see #EXTRA_NETWORK_SUGGESTION
@@ -1183,7 +1182,7 @@
      * containing configurations which they created.
      */
     @Deprecated
-    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE})
+    @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
     public List<WifiConfiguration> getConfiguredNetworks() {
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
@@ -1199,7 +1198,7 @@
 
     /** @hide */
     @SystemApi
-    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
+    @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
@@ -1656,8 +1655,7 @@
      * When the device decides to connect to one of the provided network suggestions, platform sends
      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
      * the network was created with {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()}
-     * flag set and the app holds either one of
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * flag set and the app holds
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
      *<p>
      * NOTE:
@@ -2290,7 +2288,6 @@
     /**
      * Return the results of the latest access point scan.
      * @return the list of access points found in the most recent scan. An app must hold
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
      * in order to get valid results.
      */
@@ -2601,7 +2598,7 @@
      * <p>
      * Applications need to have the following permissions to start LocalOnlyHotspot: {@link
      * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link
-     * android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}.  Callers without
+     * android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}.  Callers without
      * the permissions will trigger a {@link java.lang.SecurityException}.
      * <p>
      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
@@ -2684,7 +2681,7 @@
      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
      * <p>
      * Applications should have the
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
      * permission.  Callers without the permission will trigger a
      * {@link java.lang.SecurityException}.
      * <p>
diff --git a/wifi/java/android/net/wifi/aware/IdentityChangedListener.java b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
index 81a06e8..a8b19b3 100644
--- a/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
+++ b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
@@ -30,7 +30,7 @@
 public class IdentityChangedListener {
     /**
      * @param mac The MAC address of the Aware discovery interface. The application must have the
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to get the actual MAC address,
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the actual MAC address,
      *            otherwise all 0's will be provided.
      */
     public void onIdentityChanged(byte[] mac) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 1fa1fd5..8aef7a2 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -231,7 +231,7 @@
      * <p>
      * This version of the API attaches a listener to receive the MAC address of the Aware interface
      * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
-     * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * The application must have the {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
      * permission to execute this attach request. Otherwise, use the
      * {@link #attach(AttachCallback, Handler)} version. Note that aside from permission
      * requirements this listener will wake up the host at regular intervals causing higher power
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 5f8841c..245b304 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -133,7 +133,7 @@
      *      An application must use the {@link DiscoverySession#close()} to
      *      terminate the publish discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
-     * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * <p>The application must have the {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
      * permission to start a publish discovery session.
      *
      * @param publishConfig The {@link PublishConfig} specifying the
@@ -179,7 +179,7 @@
      *      An application must use the {@link DiscoverySession#close()} to
      *      terminate the subscribe discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
-     * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * <p>The application must have the {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
      * permission to start a subscribe discovery session.
      *
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
diff --git a/wifi/java/android/net/wifi/aware/package.html b/wifi/java/android/net/wifi/aware/package.html
index d5d962f6..c4f2e1f 100644
--- a/wifi/java/android/net/wifi/aware/package.html
+++ b/wifi/java/android/net/wifi/aware/package.html
@@ -15,7 +15,7 @@
 <ul>
     <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
     <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
-    <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
+    <li>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</li>
 </ul>
 
 <p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi Aware
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 1bed914..052ab99 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1139,7 +1139,7 @@
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void discoverPeers(Channel c, ActionListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
@@ -1183,7 +1183,7 @@
      * @param config options as described in {@link WifiP2pConfig} class
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
         checkChannel(c);
         checkP2pConfig(config);
@@ -1225,7 +1225,7 @@
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void createGroup(Channel c, ActionListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
@@ -1256,7 +1256,7 @@
      * @param config the configuration of a p2p group.
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void createGroup(@NonNull Channel c,
             @Nullable WifiP2pConfig config,
             @Nullable ActionListener listener) {
@@ -1344,7 +1344,7 @@
      * @param servInfo is a local service information.
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void addLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) {
         checkChannel(c);
         checkServiceInfo(servInfo);
@@ -1454,7 +1454,7 @@
      * @param c is the channel created at {@link #initialize}
      * @param listener for callbacks on success or failure. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void discoverServices(Channel c, ActionListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, c.putListener(listener));
@@ -1530,7 +1530,7 @@
      * @param c is the channel created at {@link #initialize}
      * @param listener for callback when peer list is available. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void requestPeers(Channel c, PeerListListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
@@ -1553,7 +1553,7 @@
      * @param c is the channel created at {@link #initialize}
      * @param listener for callback when group info is available. Can be null.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
     public void requestGroupInfo(Channel c, GroupInfoListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener));
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 7bff68a..449423f 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -60,6 +60,8 @@
         config.setPasspointManagementObjectTree(cookie);
         config.trusted = false;
         config.updateIdentifier = "1234";
+        config.fromWifiNetworkSpecifier = true;
+        config.fromWifiNetworkSuggestion = true;
         MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
@@ -76,6 +78,8 @@
         assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
         assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
+        assertTrue(config.fromWifiNetworkSpecifier);
+        assertTrue(config.fromWifiNetworkSuggestion);
 
         Parcel parcelWW = Parcel.obtain();
         reconfig.writeToParcel(parcelWW, 0);