Merge "Cleanup Filter class"
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index a908178..0f981e2 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -815,31 +815,6 @@
         }
     }
 
-    private void pullWifiBytesTransfer(
-            int tagId, long elapsedNanos, long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
-        long token = Binder.clearCallingIdentity();
-        try {
-            // TODO: Consider caching the following call to get BatteryStatsInternal.
-            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-            String[] ifaces = bs.getWifiIfaces();
-            if (ifaces.length == 0) {
-                return;
-            }
-            if (mNetworkStatsService == null) {
-                Slog.e(TAG, "NetworkStats Service is not available!");
-                return;
-            }
-            // Combine all the metrics per Uid into one record.
-            NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
-            addNetworkStats(tagId, pulledData, stats, false);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
     private void pullWifiBytesTransferByFgBg(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
@@ -2316,149 +2291,180 @@
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         long wallClockNanos = SystemClock.currentTimeMicro() * 1000L;
         switch (tagId) {
-            case StatsLog.WIFI_BYTES_TRANSFER: {
-                pullWifiBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
+            
             case StatsLog.MOBILE_BYTES_TRANSFER: {
                 pullMobileBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
                 pullWifiBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
                 pullMobileBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
                 pullBluetoothBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.KERNEL_WAKELOCK: {
                 pullKernelWakelock(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CPU_TIME_PER_FREQ: {
                 pullCpuTimePerFreq(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CPU_TIME_PER_UID: {
                 pullKernelUidCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CPU_TIME_PER_UID_FREQ: {
                 pullKernelUidCpuFreqTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CPU_CLUSTER_TIME: {
                 pullKernelUidCpuClusterTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CPU_ACTIVE_TIME: {
                 pullKernelUidCpuActiveTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.WIFI_ACTIVITY_INFO: {
                 pullWifiActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.MODEM_ACTIVITY_INFO: {
                 pullModemActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
                 pullBluetoothActivityInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.SYSTEM_UPTIME: {
                 pullSystemUpTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.SYSTEM_ELAPSED_REALTIME: {
                 pullSystemElapsedRealtime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROCESS_MEMORY_STATE: {
                 pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: {
                 pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROCESS_MEMORY_SNAPSHOT: {
                 pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.SYSTEM_ION_HEAP_SIZE: {
                 pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE: {
                 pullProcessSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.BINDER_CALLS: {
                 pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.BINDER_CALLS_EXCEPTIONS: {
                 pullBinderCallsStatsExceptions(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.LOOPER_STATS: {
                 pullLooperStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DISK_STATS: {
                 pullDiskStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DIRECTORY_USAGE: {
                 pullDirectoryUsage(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.APP_SIZE: {
                 pullAppSize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.CATEGORY_SIZE: {
                 pullCategorySize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.NUM_FINGERPRINTS_ENROLLED: {
                 pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FINGERPRINT, tagId,
                         elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.NUM_FACES_ENROLLED: {
                 pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FACE, tagId, elapsedNanos,
                         wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROC_STATS: {
                 pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROC_STATS_PKG_PROC: {
                 pullProcessStats(ProcessStats.REPORT_PKG_PROC_STATS, tagId, elapsedNanos,
                         wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DISK_IO: {
                 pullDiskIo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.POWER_PROFILE: {
                 pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.BUILD_INFORMATION: {
                 pullBuildInformation(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.PROCESS_CPU_TIME: {
                 pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
@@ -2467,73 +2473,90 @@
                 pullCpuTimePerThreadFreq(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DEVICE_CALCULATED_POWER_USE: {
                 pullDeviceCalculatedPowerUse(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: {
                 pullDeviceCalculatedPowerBlameUid(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: {
                 pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.TEMPERATURE: {
                 pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.COOLING_DEVICE: {
                 pullCoolingDevices(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DEBUG_ELAPSED_CLOCK: {
                 pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DEBUG_FAILING_ELAPSED_CLOCK: {
                 pullDebugFailingElapsedClock(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.ROLE_HOLDER: {
                 pullRoleHolders(elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DANGEROUS_PERMISSION_STATE: {
                 pullDangerousPermissionState(StatsLog.DANGEROUS_PERMISSION_STATE, elapsedNanos,
                         wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED: {
                 pullDangerousPermissionState(StatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED,
                         elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.TIME_ZONE_DATA_INFO: {
                 pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.EXTERNAL_STORAGE_INFO: {
                 pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.APPS_ON_EXTERNAL_STORAGE_INFO: {
                 pullAppsOnExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.FACE_SETTINGS: {
                 pullFaceSettings(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.APP_OPS: {
                 pullAppOps(elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             case StatsLog.NOTIFICATION_REMOTE_VIEWS: {
                 pullNotificationStats(NotificationManagerService.REPORT_REMOTE_VIEWS,
                         tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
diff --git a/api/current.txt b/api/current.txt
index 737bcb6..42318fe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -115,6 +115,7 @@
     field public static final String READ_LOGS = "android.permission.READ_LOGS";
     field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
     field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
+    field public static final String READ_PRECISE_PHONE_STATE = "android.permission.READ_PRECISE_PHONE_STATE";
     field public static final String READ_SMS = "android.permission.READ_SMS";
     field public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
     field public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
@@ -1144,6 +1145,7 @@
     field public static final int resizeable = 16843405; // 0x101028d
     field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
+    field public static final int resourcesMap = 16844297; // 0x1010609
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field @Deprecated public static final int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
@@ -10006,7 +10008,6 @@
     field public static final String MEDIA_ROUTER_SERVICE = "media_router";
     field public static final String MEDIA_SESSION_SERVICE = "media_session";
     field public static final String MIDI_SERVICE = "midi";
-    field public static final String MMS_SERVICE = "mms";
     field public static final int MODE_APPEND = 32768; // 0x8000
     field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
     field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4
@@ -11364,6 +11365,7 @@
   public class CrossProfileApps {
     method public boolean canInteractAcrossProfiles();
     method public boolean canRequestInteractAcrossProfiles();
+    method @Nullable public android.content.Intent createRequestInteractAcrossProfilesIntent();
     method @NonNull public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(@NonNull android.os.UserHandle);
     method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
     method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
@@ -30663,11 +30665,11 @@
     ctor public WifiNetworkSuggestion.Builder();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion build();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserAllowedToManuallyConnect(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
@@ -36072,6 +36074,7 @@
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(String);
     method public boolean isDemoUser();
+    method public boolean isManagedProfile();
     method public boolean isQuietModeEnabled(android.os.UserHandle);
     method public boolean isSystemUser();
     method public boolean isUserAGoat();
@@ -45539,11 +45542,6 @@
     method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
   }
 
-  public final class MmsManager {
-    method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
-    method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
-  }
-
   @Deprecated public class NeighboringCellInfo implements android.os.Parcelable {
     ctor @Deprecated public NeighboringCellInfo();
     ctor @Deprecated public NeighboringCellInfo(int, int);
@@ -45781,8 +45779,8 @@
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
     method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
     method public java.util.ArrayList<java.lang.String> divideMessage(String);
-    method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
-    method @NonNull public android.os.Bundle getCarrierConfigValues();
+    method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+    method @Nullable public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
@@ -45791,7 +45789,7 @@
     method public int getSubscriptionId();
     method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
     method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
-    method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+    method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
     method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
     method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
diff --git a/api/system-current.txt b/api/system-current.txt
index 5aff7c5..515bf54 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -241,7 +241,6 @@
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
-    field public static final int resourcesMap = 16844297; // 0x1010609
     field public static final int supportsAmbientMode = 16844173; // 0x101058d
     field public static final int userRestriction = 16844164; // 0x1010584
   }
@@ -1536,6 +1535,10 @@
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
   }
 
+  public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+  }
+
   public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
     method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
@@ -1544,12 +1547,20 @@
     field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
   }
 
+  public final class BluetoothMap implements android.bluetooth.BluetoothProfile {
+    method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int);
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
+  }
+
   public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
     method protected void finalize();
     method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
     method public boolean isTetheringOn();
     method public void setBluetoothTethering(boolean);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
     field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
     field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
     field public static final int LOCAL_NAP_ROLE = 1; // 0x1
@@ -6171,6 +6182,25 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
   }
 
+  public final class WifiOemConfigStoreMigrationHook {
+    method @Nullable public static android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData load();
+  }
+
+  public static final class WifiOemConfigStoreMigrationHook.MigrationData implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public java.util.List<android.net.wifi.WifiConfiguration> getUserSavedNetworkConfigurations();
+    method @Nullable public android.net.wifi.SoftApConfiguration getUserSoftApConfiguration();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData> CREATOR;
+  }
+
+  public static final class WifiOemConfigStoreMigrationHook.MigrationData.Builder {
+    ctor public WifiOemConfigStoreMigrationHook.MigrationData.Builder();
+    method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData build();
+    method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>);
+    method @NonNull public android.net.wifi.WifiOemConfigStoreMigrationHook.MigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+  }
+
   public class WifiScanner {
     method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
     method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
@@ -7273,7 +7303,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
@@ -8662,7 +8691,10 @@
     method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
     method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
     method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
+    method public void onNotificationVisibilityChanged(@NonNull String, boolean);
     method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
+    method public void onPanelHidden();
+    method public void onPanelRevealed(int);
     method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
     method public final void unsnoozeNotification(@NonNull String);
     field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
@@ -10411,6 +10443,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
     method public boolean isCurrentSimOperator(@NonNull String, int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
     method public boolean isDataConnectivityPossible();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
diff --git a/api/test-current.txt b/api/test-current.txt
index d017dd6..00a2c29 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -435,6 +435,8 @@
   }
 
   public class StatusBarManager {
+    method public void collapsePanels();
+    method public void expandNotificationsPanel();
     method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
     method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
     method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
@@ -2929,7 +2931,10 @@
     method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
     method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
     method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
+    method public void onNotificationVisibilityChanged(@NonNull String, boolean);
     method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
+    method public void onPanelHidden();
+    method public void onPanelRevealed(int);
     method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
     method public final void unsnoozeNotification(@NonNull String);
     field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f6680f3..2bacfbc 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -333,6 +333,7 @@
         MediaProviderSchemaChange media_provider_schema_change = 236 [(module) = "mediaprovider"];
         MediaProviderIdleMaintenance media_provider_idle_maintenance =
             237 [(module) = "mediaprovider"];
+        RebootEscrowRecoveryReported reboot_escrow_recovery_reported = 238;
     }
 
     // Pulled events will start at field 10000.
@@ -7339,6 +7340,17 @@
 }
 
 /**
+ * Reported when the RebootEscrow HAL has attempted to recover the escrowed
+ * key to indicate whether it was successful or not.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+ */
+message RebootEscrowRecoveryReported {
+    optional bool successful = 1;
+}
+
+/**
  * Global display pipeline metrics reported by SurfaceFlinger.
  * Pulled from:
  *    frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1d31873..b568033 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -59,161 +59,200 @@
 const int64_t NO_ALARM_UPDATE = INT64_MAX;
 
 std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
-        // wifi_bytes_transfer
-        {{.atomTag = android::util::WIFI_BYTES_TRANSFER},
-         {.additiveFields = {2, 3, 4, 5},
-          .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
+
         // wifi_bytes_transfer_by_fg_bg
         {{.atomTag = android::util::WIFI_BYTES_TRANSFER_BY_FG_BG},
          {.additiveFields = {3, 4, 5, 6},
           .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
+
         // mobile_bytes_transfer
         {{.atomTag = android::util::MOBILE_BYTES_TRANSFER},
          {.additiveFields = {2, 3, 4, 5},
           .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
+
         // mobile_bytes_transfer_by_fg_bg
         {{.atomTag = android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG},
          {.additiveFields = {3, 4, 5, 6},
           .puller =
                   new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
+
         // bluetooth_bytes_transfer
         {{.atomTag = android::util::BLUETOOTH_BYTES_TRANSFER},
          {.additiveFields = {2, 3},
           .puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
+
         // kernel_wakelock
         {{.atomTag = android::util::KERNEL_WAKELOCK},
          {.puller = new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+
         // subsystem_sleep_state
         {{.atomTag = android::util::SUBSYSTEM_SLEEP_STATE},
          {.puller = new SubsystemSleepStatePuller()}},
+
         // on_device_power_measurement
         {{.atomTag = android::util::ON_DEVICE_POWER_MEASUREMENT},
          {.puller = new PowerStatsPuller()}},
+
         // cpu_time_per_freq
         {{.atomTag = android::util::CPU_TIME_PER_FREQ},
          {.additiveFields = {3},
           .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+
         // cpu_time_per_uid
         {{.atomTag = android::util::CPU_TIME_PER_UID},
          {.additiveFields = {2, 3},
           .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
+
         // cpu_time_per_uid_freq
         // the throttling is 3sec, handled in
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {{.atomTag = android::util::CPU_TIME_PER_UID_FREQ},
          {.additiveFields = {4},
           .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
+
         // cpu_active_time
         // the throttling is 3sec, handled in
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {{.atomTag = android::util::CPU_ACTIVE_TIME},
          {.additiveFields = {2},
           .puller = new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
+
         // cpu_cluster_time
         // the throttling is 3sec, handled in
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {{.atomTag = android::util::CPU_CLUSTER_TIME},
          {.additiveFields = {3},
           .puller = new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
+
         // wifi_activity_energy_info
         {{.atomTag = android::util::WIFI_ACTIVITY_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
+
         // modem_activity_info
         {{.atomTag = android::util::MODEM_ACTIVITY_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+
         // bluetooth_activity_info
         {{.atomTag = android::util::BLUETOOTH_ACTIVITY_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+
         // system_elapsed_realtime
         {{.atomTag = android::util::SYSTEM_ELAPSED_REALTIME},
          {.coolDownNs = NS_PER_SEC,
           .puller = new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME),
           .pullTimeoutNs = NS_PER_SEC / 2,
          }},
+
         // system_uptime
         {{.atomTag = android::util::SYSTEM_UPTIME},
          {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+
         // remaining_battery_capacity
         {{.atomTag = android::util::REMAINING_BATTERY_CAPACITY},
          {.puller = new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
+
         // full_battery_capacity
         {{.atomTag = android::util::FULL_BATTERY_CAPACITY},
          {.puller = new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+
         // battery_voltage
         {{.atomTag = android::util::BATTERY_VOLTAGE},
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
+
         // battery_level
         {{.atomTag = android::util::BATTERY_LEVEL},
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
+
         // battery_cycle_count
         {{.atomTag = android::util::BATTERY_CYCLE_COUNT},
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
+
         // process_memory_state
         {{.atomTag = android::util::PROCESS_MEMORY_STATE},
          {.additiveFields = {4, 5, 6, 7, 8},
           .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
+
         // process_memory_high_water_mark
         {{.atomTag = android::util::PROCESS_MEMORY_HIGH_WATER_MARK},
          {.puller =
                   new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
+
         // process_memory_snapshot
         {{.atomTag = android::util::PROCESS_MEMORY_SNAPSHOT},
          {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}},
+
         // system_ion_heap_size
         {{.atomTag = android::util::SYSTEM_ION_HEAP_SIZE},
          {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
+
         // process_system_ion_heap_size
         {{.atomTag = android::util::PROCESS_SYSTEM_ION_HEAP_SIZE},
          {.puller = new StatsCompanionServicePuller(android::util::PROCESS_SYSTEM_ION_HEAP_SIZE)}},
+
         // temperature
         {{.atomTag = android::util::TEMPERATURE},
          {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
+
         // cooling_device
         {{.atomTag = android::util::COOLING_DEVICE},
          {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}},
+
         // binder_calls
         {{.atomTag = android::util::BINDER_CALLS},
          {.additiveFields = {4, 5, 6, 8, 12},
           .puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS)}},
+
         // binder_calls_exceptions
         {{.atomTag = android::util::BINDER_CALLS_EXCEPTIONS},
          {.puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}},
+
         // looper_stats
         {{.atomTag = android::util::LOOPER_STATS},
          {.additiveFields = {5, 6, 7, 8, 9},
           .puller = new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
+
         // Disk Stats
         {{.atomTag = android::util::DISK_STATS},
          {.puller = new StatsCompanionServicePuller(android::util::DISK_STATS)}},
+
         // Directory usage
         {{.atomTag = android::util::DIRECTORY_USAGE},
          {.puller = new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
+
         // Size of app's code, data, and cache
         {{.atomTag = android::util::APP_SIZE},
          {.puller = new StatsCompanionServicePuller(android::util::APP_SIZE)}},
+
         // Size of specific categories of files. Eg. Music.
         {{.atomTag = android::util::CATEGORY_SIZE},
          {.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
+
         // Number of fingerprints enrolled for each user.
         {{.atomTag = android::util::NUM_FINGERPRINTS_ENROLLED},
          {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS_ENROLLED)}},
+
         // Number of faces enrolled for each user.
         {{.atomTag = android::util::NUM_FACES_ENROLLED},
          {.puller = new StatsCompanionServicePuller(android::util::NUM_FACES_ENROLLED)}},
+
         // ProcStats.
         {{.atomTag = android::util::PROC_STATS},
          {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}},
+
         // ProcStatsPkgProc.
         {{.atomTag = android::util::PROC_STATS_PKG_PROC},
          {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
+
         // Disk I/O stats per uid.
         {{.atomTag = android::util::DISK_IO},
          {.additiveFields = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
           .coolDownNs = 3 * NS_PER_SEC,
           .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}},
+
         // PowerProfile constants for power model calculations.
         {{.atomTag = android::util::POWER_PROFILE},
          {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
+
         // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
         {{.atomTag = android::util::PROCESS_CPU_TIME},
          {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/,
@@ -221,64 +260,83 @@
         {{.atomTag = android::util::CPU_TIME_PER_THREAD_FREQ},
          {.additiveFields = {7, 9, 11, 13, 15, 17, 19, 21},
           .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
+
         // DeviceCalculatedPowerUse.
         {{.atomTag = android::util::DEVICE_CALCULATED_POWER_USE},
          {.puller = new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
+
         // DeviceCalculatedPowerBlameUid.
         {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_UID},
          {.puller = new StatsCompanionServicePuller(
                   android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
+
         // DeviceCalculatedPowerBlameOther.
         {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER},
          {.puller = new StatsCompanionServicePuller(
                   android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
+
         // DebugElapsedClock.
         {{.atomTag = android::util::DEBUG_ELAPSED_CLOCK},
          {.additiveFields = {1, 2, 3, 4},
           .puller = new StatsCompanionServicePuller(android::util::DEBUG_ELAPSED_CLOCK)}},
+
         // DebugFailingElapsedClock.
         {{.atomTag = android::util::DEBUG_FAILING_ELAPSED_CLOCK},
          {.additiveFields = {1, 2, 3, 4},
           .puller = new StatsCompanionServicePuller(android::util::DEBUG_FAILING_ELAPSED_CLOCK)}},
+
         // BuildInformation.
         {{.atomTag = android::util::BUILD_INFORMATION},
          {.puller = new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}},
+
         // RoleHolder.
         {{.atomTag = android::util::ROLE_HOLDER},
          {.puller = new StatsCompanionServicePuller(android::util::ROLE_HOLDER)}},
+
         // PermissionState.
         {{.atomTag = android::util::DANGEROUS_PERMISSION_STATE},
          {.puller = new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE)}},
+
         // TrainInfo.
         {{.atomTag = android::util::TRAIN_INFO}, {.puller = new TrainInfoPuller()}},
+
         // TimeZoneDataInfo.
         {{.atomTag = android::util::TIME_ZONE_DATA_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
+
         // ExternalStorageInfo
         {{.atomTag = android::util::EXTERNAL_STORAGE_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}},
+
         // GpuStatsGlobalInfo
         {{.atomTag = android::util::GPU_STATS_GLOBAL_INFO},
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
+
         // GpuStatsAppInfo
         {{.atomTag = android::util::GPU_STATS_APP_INFO},
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}},
+
         // AppsOnExternalStorageInfo
         {{.atomTag = android::util::APPS_ON_EXTERNAL_STORAGE_INFO},
          {.puller = new StatsCompanionServicePuller(android::util::APPS_ON_EXTERNAL_STORAGE_INFO)}},
+
         // Face Settings
         {{.atomTag = android::util::FACE_SETTINGS},
          {.puller = new StatsCompanionServicePuller(android::util::FACE_SETTINGS)}},
+
         // App ops
         {{.atomTag = android::util::APP_OPS},
          {.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}},
+
         // VmsClientStats
         {{.atomTag = android::util::VMS_CLIENT_STATS},
          {.additiveFields = {5, 6, 7, 8, 9, 10},
           .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}},
+
         // NotiifcationRemoteViews.
         {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS},
          {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}},
+
         // PermissionStateSampled.
         {{.atomTag = android::util::DANGEROUS_PERMISSION_STATE_SAMPLED},
          {.puller =
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 700b3c1..e5c046c 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -68,6 +68,7 @@
 import android.os.WorkSource;
 import android.service.voice.IVoiceInteractionSession;
 import android.view.IRecentsAnimationRunner;
+import android.view.ITaskOrganizer;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationAdapter;
 import android.view.WindowContainerTransaction;
@@ -121,6 +122,9 @@
             in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
             int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
             IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
+
+    void registerTaskOrganizer(in ITaskOrganizer organizer, int windowingMode);
+
     boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
             int userId);
 
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 844e72e..736efb6 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -15,6 +15,7 @@
  */
 
 package android.app;
+
 import android.annotation.NonNull;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -23,6 +24,7 @@
 
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -164,6 +166,7 @@
     private static final String TAG = "PropertyInvalidatedCache";
     private static final boolean DEBUG = false;
     private static final boolean ENABLE = true;
+    private static final boolean VERIFY = false;
 
     private final Object mLock = new Object();
 
@@ -228,6 +231,18 @@
     protected abstract Result recompute(Query query);
 
     /**
+     * Determines if a pair of responses are considered equal. Used to determine whether
+     * a cache is inadvertently returning stale results when VERIFY is set to true.
+     */
+    protected boolean debugCompareQueryResults(Result cachedResult, Result fetchedResult) {
+        // If a service crashes and returns a null result, the cached value remains valid.
+        if (fetchedResult != null) {
+            return Objects.equals(cachedResult, fetchedResult);
+        }
+        return true;
+    }
+
+    /**
      * Make result up-to-date on a cache hit.  Called unlocked;
      * may block.
      *
@@ -334,12 +349,12 @@
                             mCache.put(query, refreshedResult);
                         }
                     }
-                    return refreshedResult;
+                    return maybeCheckConsistency(query, refreshedResult);
                 }
                 if (DEBUG) {
                     Log.d(TAG, "cache hit for " + query);
                 }
-                return cachedResult;
+                return maybeCheckConsistency(query, cachedResult);
             }
             // Cache miss: make the value from scratch.
             if (DEBUG) {
@@ -353,7 +368,7 @@
                     mCache.put(query, result);
                 }
             }
-            return result;
+            return maybeCheckConsistency(query, result);
         }
     }
 
@@ -425,4 +440,15 @@
         }
         SystemProperties.set(name, newValueString);
     }
+
+    private Result maybeCheckConsistency(Query query, Result proposedResult) {
+        if (VERIFY) {
+            Result resultToCompare = recompute(query);
+            boolean nonceChanged = (getCurrentNonce() != mLastSeenNonce);
+            if (!nonceChanged && !debugCompareQueryResults(proposedResult, resultToCompare)) {
+                throw new AssertionError("cache returned out of date response for " + query);
+            }
+        }
+        return proposedResult;
+    }
 }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 078e453..42563b5 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -267,6 +267,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @TestApi
     public void expandNotificationsPanel() {
         try {
             final IStatusBarService svc = getService();
@@ -284,6 +285,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @TestApi
     public void collapsePanels() {
         try {
             final IStatusBarService svc = getService();
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index e9b0be2..a923be6 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -16,8 +16,12 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
@@ -36,6 +40,7 @@
  */
 public final class BluetoothHidDevice implements BluetoothProfile {
     private static final String TAG = BluetoothHidDevice.class.getSimpleName();
+    private static final boolean DBG = false;
 
     /**
      * Intent used to broadcast the change in connection state of the Input Host profile.
@@ -682,4 +687,62 @@
 
         return result;
     }
+
+    /**
+     * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}
+     * and disconnects Hid device if connectionPolicy is
+     * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}.
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of:
+     * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
+     * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
+     * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy determines whether hid device should be connected or disconnected
+     * @return true if hid device is connected or disconnected, false otherwise
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+        try {
+            final IBluetoothHidDevice service = getService();
+            if (service != null && isEnabled()
+                    && isValidDevice(device)) {
+                if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                        && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+                    return false;
+                }
+                return service.setConnectionPolicy(device, connectionPolicy);
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+            return false;
+        }
+    }
+
+    private boolean isEnabled() {
+        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+        return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+        if (device == null) return false;
+
+        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+        return false;
+    }
+
+    private static void log(String msg) {
+        if (DBG) {
+            Log.d(TAG, msg);
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 917e7fa..4674706 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -17,7 +17,10 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -35,21 +38,35 @@
  *
  * @hide
  */
+@SystemApi
 public final class BluetoothMap implements BluetoothProfile {
 
     private static final String TAG = "BluetoothMap";
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
+    /** @hide */
+    @SuppressLint("ActionValue")
+    @SystemApi
     public static final String ACTION_CONNECTION_STATE_CHANGED =
             "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
 
-    /** There was an error trying to obtain the state */
+    /**
+     * There was an error trying to obtain the state
+     *
+     * @hide
+     */
     public static final int STATE_ERROR = -1;
 
+    /** @hide */
     public static final int RESULT_FAILURE = 0;
+    /** @hide */
     public static final int RESULT_SUCCESS = 1;
-    /** Connection canceled before completion. */
+    /**
+     * Connection canceled before completion.
+     *
+     * @hide
+     */
     public static final int RESULT_CANCELED = 2;
 
     private BluetoothAdapter mAdapter;
@@ -71,6 +88,7 @@
         mProfileConnector.connect(context, listener);
     }
 
+    @SuppressLint("GenericException")
     protected void finalize() throws Throwable {
         try {
             close();
@@ -84,6 +102,8 @@
      * Other public functions of BluetoothMap will return default error
      * results once close() has been called. Multiple invocations of close()
      * are ok.
+     *
+     * @hide
      */
     public synchronized void close() {
         mProfileConnector.disconnect();
@@ -98,6 +118,8 @@
      *
      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
      * connected to the Map service.
+     *
+     * @hide
      */
     public int getState() {
         if (VDBG) log("getState()");
@@ -120,6 +142,8 @@
      *
      * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
      * this proxy object is not connected to the Map service.
+     *
+     * @hide
      */
     public BluetoothDevice getClient() {
         if (VDBG) log("getClient()");
@@ -141,6 +165,8 @@
      * Returns true if the specified Bluetooth device is connected.
      * Returns false if not connected, or if this proxy object is not
      * currently connected to the Map service.
+     *
+     * @hide
      */
     public boolean isConnected(BluetoothDevice device) {
         if (VDBG) log("isConnected(" + device + ")");
@@ -161,6 +187,8 @@
     /**
      * Initiate connection. Initiation of outgoing connections is not
      * supported for MAP server.
+     *
+     * @hide
      */
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
@@ -172,6 +200,8 @@
      *
      * @param device Remote Bluetooth Device
      * @return false on error, true otherwise
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public boolean disconnect(BluetoothDevice device) {
@@ -196,6 +226,8 @@
      * devices. It tries to err on the side of false positives.
      *
      * @return True if this device might support Map.
+     *
+     * @hide
      */
     public static boolean doesClassMatchSink(BluetoothClass btClass) {
         // TODO optimize the rule
@@ -214,8 +246,11 @@
      * Get the list of connected devices. Currently at most one.
      *
      * @return list of connected devices
+     *
+     * @hide
      */
-    public List<BluetoothDevice> getConnectedDevices() {
+    @SystemApi
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
         if (DBG) log("getConnectedDevices()");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled()) {
@@ -234,6 +269,8 @@
      * Get the list of devices matching specified states. Currently at most one.
      *
      * @return list of matching devices
+     *
+     * @hide
      */
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         if (DBG) log("getDevicesMatchingStates()");
@@ -254,6 +291,8 @@
      * Get connection state of device
      *
      * @return device connection state
+     *
+     * @hide
      */
     public int getConnectionState(BluetoothDevice device) {
         if (DBG) log("getConnectionState(" + device + ")");
@@ -301,7 +340,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -349,7 +388,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 42f27f2..024bb06 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -16,9 +16,11 @@
 
 package android.bluetooth;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SuppressLint;
@@ -256,6 +258,41 @@
     }
 
     /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+        try {
+            final IBluetoothPan service = getService();
+            if (service != null && isEnabled()
+                    && isValidDevice(device)) {
+                if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                        && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+                    return false;
+                }
+                return service.setConnectionPolicy(device, connectionPolicy);
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+            return false;
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 948885e..e07ca52 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -274,15 +274,15 @@
     }
 
     /**
-     * Pbap does not store connection policy, so this function only disconnects Pbap if
-     * connectionPolicy is CONNECTION_POLICY_FORBIDDEN.
+     * Pbap does not store connection policy, so this function only disconnects pbap if
+     * connectionPolicy is {@link #CONNECTION_POLICY_FORBIDDEN}.
      *
      * <p> The device should already be paired.
      * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
      * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
      *
      * @param device Paired bluetooth device
-     * @param connectionPolicy is the connection policy to set to for this profile
+     * @param connectionPolicy determines whether to disconnect the device
      * @return true if pbap is successfully disconnected, false otherwise
      * @hide
      */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 1b40a18..44b2df6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3416,7 +3416,6 @@
             TELEPHONY_SUBSCRIPTION_SERVICE,
             CARRIER_CONFIG_SERVICE,
             EUICC_SERVICE,
-            MMS_SERVICE,
             TELECOM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
@@ -3613,8 +3612,6 @@
      * @see android.telephony.CarrierConfigManager
      * @see #EUICC_SERVICE
      * @see android.telephony.euicc.EuiccManager
-     * @see #MMS_SERVICE
-     * @see android.telephony.MmsManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
@@ -4291,15 +4288,6 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.telephony.MmsManager} to send/receive MMS messages.
-     *
-     * @see #getSystemService(String)
-     * @see android.telephony.MmsManager
-     */
-    public static final String MMS_SERVICE = "mms";
-
-    /**
-     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.content.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index abf32c5e..9d57514 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -16,15 +16,19 @@
 package android.content.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 
 import com.android.internal.R;
 import com.android.internal.util.UserIcons;
@@ -226,6 +230,30 @@
         }
     }
 
+    /**
+     * Returns an {@link Intent} to open the settings page that allows the user to decide whether
+     * the calling app can interact across profiles. The current state is given by
+     * {@link #canInteractAcrossProfiles()}.
+     *
+     * <p>Returns {@code null} if {@link #canRequestInteractAcrossProfiles()} is {@code false}.
+     *
+     * @return an {@link Intent} to open the settings page that allows the user to decide whether
+     * the app can interact across profiles
+     *
+     * @throws SecurityException if {@code mContext.getPackageName()} does not belong to the
+     * calling UID.
+     */
+    public @Nullable Intent createRequestInteractAcrossProfilesIntent() {
+        if (!canRequestInteractAcrossProfiles()) {
+            return null;
+        }
+        final Intent settingsIntent = new Intent();
+        settingsIntent.setAction(Settings.ACTION_MANAGE_CROSS_PROFILE_ACCESS);
+        final Uri packageUri = Uri.parse("package:" + mContext.getPackageName());
+        settingsIntent.setData(packageUri);
+        return settingsIntent;
+    }
+
     private void verifyCanAccessUser(UserHandle userHandle) {
         if (!getTargetUserProfiles().contains(userHandle)) {
             throw new SecurityException("Not allowed to access " + userHandle);
diff --git a/core/java/android/content/res/TEST_MAPPING b/core/java/android/content/res/TEST_MAPPING
new file mode 100644
index 0000000..daf9a14
--- /dev/null
+++ b/core/java/android/content/res/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksResourceLoaderTests"
+    }
+  ]
+}
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 6378db0..b273cd6 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -76,6 +76,11 @@
      */
     private final boolean mIsApex;
 
+    /**
+     * Whether this instance represents the PackageRollbackInfo for an APK in APEX.
+     */
+    private final boolean mIsApkInApex;
+
     /*
      * The list of users for which snapshots have been saved.
      */
@@ -157,6 +162,10 @@
     public @PackageManager.RollbackDataPolicy int getRollbackDataPolicy() {
         return mRollbackDataPolicy;
     }
+    /** @hide */
+    public boolean isApkInApex() {
+        return mIsApkInApex;
+    }
 
     /** @hide */
     public IntArray getSnapshottedUsers() {
@@ -190,17 +199,18 @@
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
             @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
-            boolean isApex, @NonNull IntArray snapshottedUsers,
+            boolean isApex, boolean isApkInApex, @NonNull IntArray snapshottedUsers,
             @NonNull SparseLongArray ceSnapshotInodes) {
         this(packageRolledBackFrom, packageRolledBackTo, pendingBackups, pendingRestores, isApex,
-                snapshottedUsers, ceSnapshotInodes, PackageManager.RollbackDataPolicy.RESTORE);
+                isApkInApex, snapshottedUsers, ceSnapshotInodes,
+                PackageManager.RollbackDataPolicy.RESTORE);
     }
 
     /** @hide */
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
             @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
-            boolean isApex, @NonNull IntArray snapshottedUsers,
+            boolean isApex, boolean isApkInApex, @NonNull IntArray snapshottedUsers,
             @NonNull SparseLongArray ceSnapshotInodes,
             @PackageManager.RollbackDataPolicy int rollbackDataPolicy) {
         this.mVersionRolledBackFrom = packageRolledBackFrom;
@@ -209,6 +219,7 @@
         this.mPendingRestores = pendingRestores;
         this.mIsApex = isApex;
         this.mRollbackDataPolicy = rollbackDataPolicy;
+        this.mIsApkInApex = isApkInApex;
         this.mSnapshottedUsers = snapshottedUsers;
         this.mCeSnapshotInodes = ceSnapshotInodes;
     }
@@ -217,6 +228,7 @@
         this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
         this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
         this.mIsApex = in.readBoolean();
+        this.mIsApkInApex = in.readBoolean();
         this.mPendingRestores = null;
         this.mPendingBackups = null;
         this.mSnapshottedUsers = null;
@@ -234,6 +246,7 @@
         mVersionRolledBackFrom.writeToParcel(out, flags);
         mVersionRolledBackTo.writeToParcel(out, flags);
         out.writeBoolean(mIsApex);
+        out.writeBoolean(mIsApkInApex);
     }
 
     public static final @NonNull Parcelable.Creator<PackageRollbackInfo> CREATOR =
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 6e199ce3..d8fadfb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1850,10 +1850,7 @@
      * Checks if the calling app is running in a managed profile.
      *
      * @return whether the caller is in a managed profile.
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isManagedProfile() {
         // No need for synchronization.  Once it becomes non-null, it'll be non-null forever.
         // Worst case we might end up calling the AIDL method multiple times but that's fine.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0680523..a31c3d1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -389,6 +389,21 @@
             "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
 
     /**
+     * Activity Action: Show settings to allow configuration of cross-profile access for apps
+     *
+     * Input: Optionally, the Intent's data URI can specify the application package name to
+     * directly invoke the management GUI specific to the package name. For example
+     * "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_CROSS_PROFILE_ACCESS =
+            "android.settings.MANAGE_CROSS_PROFILE_ACCESS";
+
+    /**
      * Activity Action: Show the "Open by Default" page in a particular application's details page.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 5977baf..4ead3fc 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -49,6 +49,9 @@
     void onNotificationEnqueuedWithChannel(in IStatusBarNotificationHolder notificationHolder, in NotificationChannel channel);
     void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
     void onNotificationsSeen(in List<String> keys);
+    void onPanelRevealed(int items);
+    void onPanelHidden();
+    void onNotificationVisibilityChanged(String key, boolean isVisible);
     void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
     void onNotificationDirectReply(String key);
     void onSuggestedReplySent(String key, in CharSequence reply, int source);
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index da40254..e976e18 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -182,6 +182,32 @@
     }
 
     /**
+     * Implement this to know when the notification panel is revealed
+     *
+     * @param items Number of items on the panel at time of opening
+     */
+    public void onPanelRevealed(int items) {
+
+    }
+
+    /**
+     * Implement this to know when the notification panel is hidden
+     */
+    public void onPanelHidden() {
+
+    }
+
+    /**
+     * Implement this to know when a notification becomes visible or hidden from the user.
+     *
+     * @param key the notification key
+     * @param isVisible whether the notification is visible.
+     */
+    public void onNotificationVisibilityChanged(@NonNull String key, boolean isVisible) {
+
+    }
+
+    /**
      * Implement this to know when a notification change (expanded / collapsed) is visible to user.
      *
      * @param key the notification key
@@ -337,6 +363,30 @@
         }
 
         @Override
+        public void onPanelRevealed(int items) {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = items;
+            mHandler.obtainMessage(MyHandler.MSG_ON_PANEL_REVEALED,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onPanelHidden() {
+            SomeArgs args = SomeArgs.obtain();
+            mHandler.obtainMessage(MyHandler.MSG_ON_PANEL_HIDDEN,
+                    args).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, boolean isVisible) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.argi1 = isVisible ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED,
+                    args).sendToTarget();
+        }
+
+        @Override
         public void onNotificationExpansionChanged(String key, boolean isUserAction,
                 boolean isExpanded) {
             SomeArgs args = SomeArgs.obtain();
@@ -394,6 +444,9 @@
         public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6;
         public static final int MSG_ON_ACTION_INVOKED = 7;
         public static final int MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED = 8;
+        public static final int MSG_ON_PANEL_REVEALED = 9;
+        public static final int MSG_ON_PANEL_HIDDEN = 10;
+        public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 11;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -480,6 +533,25 @@
                     onAllowedAdjustmentsChanged();
                     break;
                 }
+                case MSG_ON_PANEL_REVEALED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    int items = args.argi1;
+                    args.recycle();
+                    onPanelRevealed(items);
+                    break;
+                }
+                case MSG_ON_PANEL_HIDDEN: {
+                    onPanelHidden();
+                    break;
+                }
+                case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    String key = (String) args.arg1;
+                    boolean isVisible = args.argi1 == 1;
+                    args.recycle();
+                    onNotificationVisibilityChanged(key, isVisible);
+                    break;
+                }
             }
         }
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 80d054b..fd04f49 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1383,6 +1383,22 @@
         }
 
         @Override
+        public void onPanelRevealed(int items) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onPanelHidden() throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(
+                String key, boolean isVisible) {
+            // no-op in the listener
+        }
+
+        @Override
         public void onNotificationSnoozedUntilContext(
                 IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId)
                 throws RemoteException {
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
new file mode 100644
index 0000000..e92aafe
--- /dev/null
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -0,0 +1,38 @@
+/* //device/java/android/android/view/ITaskOrganizer.aidl
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.view;
+
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
+import android.app.ActivityManager;
+
+/**
+ * Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
+ * {@hide}
+ */
+oneway interface ITaskOrganizer {
+    void taskAppeared(in IWindowContainer container,
+        in ActivityManager.RunningTaskInfo taskInfo);
+    void taskVanished(in IWindowContainer container);
+
+    /**
+     * Called upon completion of
+     * ActivityTaskManagerService#applyTaskOrganizerTransaction
+     */
+    void transactionReady(int id, in SurfaceControl.Transaction t);
+}
\ No newline at end of file
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index 607a870..253794f 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -62,6 +62,18 @@
         return this;
     }
 
+    /**
+     * Notify activies within the hiearchy of a container that they have entered picture-in-picture
+     * mode with the given bounds.
+     */
+    public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
+            Rect bounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mSchedulePipCallback = true;
+        chg.mPinnedBounds = new Rect(bounds);
+        return this;
+    }
+
     public Map<IBinder, Change> getChanges() {
         return mChanges;
     }
@@ -104,12 +116,20 @@
         private @ActivityInfo.Config int mConfigSetMask = 0;
         private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
 
+        private boolean mSchedulePipCallback = false;
+        private Rect mPinnedBounds = null;
+
         public Change() {}
 
         protected Change(Parcel in) {
             mConfiguration.readFromParcel(in);
             mConfigSetMask = in.readInt();
             mWindowSetMask = in.readInt();
+            mSchedulePipCallback = (in.readInt() != 0);
+            if (mSchedulePipCallback ) {
+                mPinnedBounds = new Rect();
+                mPinnedBounds.readFromParcel(in);
+            }
         }
 
         public Configuration getConfiguration() {
@@ -126,6 +146,14 @@
             return mWindowSetMask;
         }
 
+        /**
+         * Returns the bounds to be used for scheduling the enter pip callback
+         * or null if no callback is to be scheduled.
+         */
+        public Rect getEnterPipBounds() {
+            return mPinnedBounds;
+        }
+
         @Override
         public String toString() {
             final boolean changesBounds =
@@ -151,6 +179,11 @@
             mConfiguration.writeToParcel(dest, flags);
             dest.writeInt(mConfigSetMask);
             dest.writeInt(mWindowSetMask);
+
+            dest.writeInt(mSchedulePipCallback ? 1 : 0);
+            if (mSchedulePipCallback ) {
+                mPinnedBounds.writeToParcel(dest, flags);
+            }
         }
 
         @Override
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index d86766e..01a0e9b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -565,7 +565,8 @@
     }
 
     private static void visitIconUri(Icon icon, @NonNull Consumer<Uri> visitor) {
-        if (icon != null && icon.getType() == Icon.TYPE_URI) {
+        if (icon != null && (icon.getType() == Icon.TYPE_URI
+                || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
             visitor.accept(icon.getUri());
         }
     }
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index cca97f6..3a450de 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.logging;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 /**
  * Logging interface for UI events. Normal implementation is UiEventLoggerImpl.
  * For testing, use fake implementation UiEventLoggerFake.
@@ -26,13 +29,24 @@
     /** Put your Event IDs in enums that implement this interface, and document them using the
      * UiEventEnum annotation.
      * Event IDs must be globally unique. This will be enforced by tooling (forthcoming).
-     * OEMs should use event IDs above 100000.
+     * OEMs should use event IDs above 100000 and below 1000000 (1 million).
      */
     interface UiEventEnum {
         int getId();
     }
+
     /**
-     * Log a simple event, with no package or instance ID.
+     * Log a simple event, with no package information. Does nothing if event.getId() <= 0.
+     * @param event an enum implementing UiEventEnum interface.
      */
-    void log(UiEventEnum eventID);
+    void log(@NonNull UiEventEnum event);
+
+    /**
+     * Log an event with package information. Does nothing if event.getId() <= 0.
+     * Give both uid and packageName if both are known, but one may be omitted if unknown.
+     * @param event an enum implementing UiEventEnum interface.
+     * @param uid the uid of the relevant app, if known (0 otherwise).
+     * @param packageName the package name of the relevant app, if known (null otherwise).
+     */
+    void log(@NonNull UiEventEnum event, int uid, @Nullable String packageName);
 }
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index e64fba2..bdf460c 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -24,14 +24,16 @@
  * See UiEventReported atom in atoms.proto for more context.
  */
 public class UiEventLoggerImpl implements UiEventLogger {
-    /**
-     * Log a simple event, with no package or instance ID.
-     */
     @Override
     public void log(UiEventEnum event) {
+        log(event, 0, null);
+    }
+
+    @Override
+    public void log(UiEventEnum event, int uid, String packageName) {
         final int eventID = event.getId();
         if (eventID > 0) {
-            StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, 0, null);
+            StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, uid, packageName);
         }
     }
 }
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 92e9bbb..6be5b81 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -30,7 +30,7 @@
     /**
      * Immutable data class used to record fake log events.
      */
-    public class FakeUiEvent {
+    public static class FakeUiEvent {
         public final int eventId;
         public final int uid;
         public final String packageName;
@@ -44,15 +44,20 @@
 
     private Queue<FakeUiEvent> mLogs = new LinkedList<FakeUiEvent>();
 
-    @Override
-    public void log(UiEventEnum event) {
-        final int eventId = event.getId();
-        if (eventId > 0) {
-            mLogs.offer(new FakeUiEvent(eventId, 0, null));
-        }
-    }
-
     public Queue<FakeUiEvent> getLogs() {
         return mLogs;
     }
+
+    @Override
+    public void log(UiEventEnum event) {
+        log(event, 0, null);
+    }
+
+    @Override
+    public void log(UiEventEnum event, int uid, String packageName) {
+        final int eventId = event.getId();
+        if (eventId > 0) {
+            mLogs.offer(new FakeUiEvent(eventId, uid, packageName));
+        }
+    }
 }
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
index c6925f4..70627ed 100644
--- a/core/proto/android/server/animationadapter.proto
+++ b/core/proto/android/server/animationadapter.proto
@@ -50,7 +50,6 @@
     optional WindowAnimationSpecProto window = 1;
     optional MoveAnimationSpecProto move = 2;
     optional AlphaAnimationSpecProto alpha = 3;
-    optional RotationAnimationSpecProto rotate = 4;
 }
 
 /* represents WindowAnimationSpec */
@@ -77,12 +76,3 @@
     optional float to = 2;
     optional int64 duration_ms = 3;
 }
-
-/* represents RotationAnimationSpec */
-message RotationAnimationSpecProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional float start_luma = 1;
-    optional float end_luma = 2;
-    optional int64 duration_ms = 3;
-}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d887032..c050146 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2071,8 +2071,10 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- Allows read only access to precise phone state.
-         @hide Pending API council approval -->
+         Allows reading of detailed information about phone state for special-use applications
+         such as dialers, carrier applications, or ims applications. -->
     <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows read access to privileged phone state.
diff --git a/core/res/res/anim/screen_rotate_0_enter.xml b/core/res/res/anim/screen_rotate_0_enter.xml
index 629be7e..93cf365 100644
--- a/core/res/res/anim/screen_rotate_0_enter.xml
+++ b/core/res/res/anim/screen_rotate_0_enter.xml
@@ -1,25 +1,25 @@
 <?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.
-  -->
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:interpolator="@interpolator/screen_rotation_alpha_in"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:duration="@android:integer/config_screen_rotation_fade_in" />
+        android:shareInterpolator="false">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml
index fa046a0..37d5a411 100644
--- a/core/res/res/anim/screen_rotate_0_exit.xml
+++ b/core/res/res/anim/screen_rotate_0_exit.xml
@@ -1,25 +1,22 @@
 <?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.
-  -->
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:interpolator="@interpolator/screen_rotation_alpha_out"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:duration="@android:integer/config_screen_rotation_fade_out" />
+        android:shareInterpolator="false">
 </set>
diff --git a/core/res/res/anim/screen_rotate_0_frame.xml b/core/res/res/anim/screen_rotate_0_frame.xml
new file mode 100644
index 0000000..5ea9bf8
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_0_frame.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 889a615..688a8d5 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -18,11 +18,11 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
     <rotate android:fromDegrees="180" android:toDegrees="0"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_180" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index 766fcfa..58a1868 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -18,11 +18,11 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
     <rotate android:fromDegrees="0" android:toDegrees="-180"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_180" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_alpha.xml b/core/res/res/anim/screen_rotate_alpha.xml
index 2cac982..c49ef9c 100644
--- a/core/res/res/anim/screen_rotate_alpha.xml
+++ b/core/res/res/anim/screen_rotate_alpha.xml
@@ -20,8 +20,8 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-           android:interpolator="@interpolator/screen_rotation_alpha_out"
+           android:interpolator="@interpolator/decelerate_quint"
            android:fillEnabled="true"
            android:fillBefore="true" android:fillAfter="true"
-           android:duration="@android:integer/config_screen_rotation_fade_out" />
+           android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index 87fd25e..b16d5fc 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -18,17 +18,19 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
+    <!-- Version for two-phase anim
     <rotate android:fromDegrees="-90" android:toDegrees="0"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_90" />
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/screen_rotation_alpha_in"
-        android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
-        android:duration="@android:integer/config_screen_rotation_fade_in" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_longAnimTime" />
+    -->
+    <rotate android:fromDegrees="-90" android:toDegrees="0"
+            android:pivotX="50%" android:pivotY="50%"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index c3aee14..0927dd3 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -18,16 +18,26 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
+    <!-- Version for two-phase animation
     <rotate android:fromDegrees="0" android:toDegrees="90"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_90" />
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/screen_rotation_alpha_out"
-        android:duration="@android:integer/config_screen_rotation_fade_out" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_longAnimTime" />
+    -->
+    <scale android:fromXScale="100%" android:toXScale="100%p"
+            android:fromYScale="100%" android:toYScale="100%p"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
+    <rotate android:fromDegrees="0" android:toDegrees="90"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 8849db4..86a8d24 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -18,16 +18,19 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
+    <!-- Version for two-phase animation
     <rotate android:fromDegrees="90" android:toDegrees="0"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_90" />
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:fillEnabled="true"
-        android:interpolator="@interpolator/screen_rotation_alpha_in"
-        android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
-        android:duration="@android:integer/config_screen_rotation_fade_in" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_longAnimTime" />
+    -->
+    <rotate android:fromDegrees="90" android:toDegrees="0"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index de84c3b..fd786f9 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -18,16 +18,26 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
+        android:shareInterpolator="false">
+    <!-- Version for two-phase animation
     <rotate android:fromDegrees="0" android:toDegrees="-90"
-        android:pivotX="50%" android:pivotY="50%"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="@android:integer/config_screen_rotation_total_90" />
-    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-        android:interpolator="@interpolator/screen_rotation_alpha_out"
-        android:fillEnabled="true"
-        android:fillBefore="true" android:fillAfter="true"
-        android:duration="@android:integer/config_screen_rotation_fade_out" />
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_longAnimTime" />
+    -->
+    <scale android:fromXScale="100%" android:toXScale="100%p"
+            android:fromYScale="100%" android:toYScale="100%p"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
+    <rotate android:fromDegrees="0" android:toDegrees="-90"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_in.xml b/core/res/res/interpolator/screen_rotation_alpha_in.xml
deleted file mode 100644
index 9c566a7..0000000
--- a/core/res/res/interpolator/screen_rotation_alpha_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-  -->
-
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:controlX1="0.15"
-    android:controlY1="0.45"
-    android:controlX2="0.33"
-    android:controlY2="1"/>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_out.xml b/core/res/res/interpolator/screen_rotation_alpha_out.xml
deleted file mode 100644
index 73a37d4..0000000
--- a/core/res/res/interpolator/screen_rotation_alpha_out.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-  -->
-
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:controlX1="0.57"
-    android:controlY1="0"
-    android:controlX2="0.71"
-    android:controlY2=".43"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 245aed1..6691d4c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -147,24 +147,6 @@
     <integer name="config_activityShortDur">150</integer>
     <integer name="config_activityDefaultDur">220</integer>
 
-    <!-- Fade out time for screen rotation -->
-    <integer name="config_screen_rotation_fade_out">116</integer>
-
-    <!-- Fade in time for screen rotation -->
-    <integer name="config_screen_rotation_fade_in">233</integer>
-
-    <!-- Fade in delay time for screen rotation -->
-    <integer name="config_screen_rotation_fade_in_delay">100</integer>
-
-    <!-- Total time for 90 degree screen rotation animations -->
-    <integer name="config_screen_rotation_total_90">333</integer>
-
-    <!-- Total time for 180 degree screen rotation animation -->
-    <integer name="config_screen_rotation_total_180">433</integer>
-
-    <!-- Total time for the rotation background color transition -->
-    <integer name="config_screen_rotation_color_transition">200</integer>
-
     <!-- The duration (in milliseconds) of the tooltip show/hide animations. -->
     <integer name="config_tooltipAnimTime">150</integer>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 817ccde..37c9710 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3000,7 +3000,6 @@
     <public-group type="attr" first-id="0x01010607">
       <public name="importantForContentCapture" />
       <public name="forceQueryable" />
-      <!-- @hide @SystemApi -->
       <public name="resourcesMap" />
       <public name="animatedImageDrawable"/>
       <public name="htmlDescription"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 973d5f6..9e11749 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1805,6 +1805,7 @@
   <!-- From services -->
   <java-symbol type="anim" name="screen_rotate_0_enter" />
   <java-symbol type="anim" name="screen_rotate_0_exit" />
+  <java-symbol type="anim" name="screen_rotate_0_frame" />
   <java-symbol type="anim" name="screen_rotate_180_enter" />
   <java-symbol type="anim" name="screen_rotate_180_exit" />
   <java-symbol type="anim" name="screen_rotate_180_frame" />
@@ -1980,7 +1981,6 @@
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
   <java-symbol type="integer" name="config_brightness_ramp_rate_slow" />
-  <java-symbol type="integer" name="config_screen_rotation_color_transition" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index c6c0b46..b13bcd1 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.net.wifi.ScanResult;
@@ -107,7 +108,7 @@
 
     @Test
     public void createFromScanResult_nullSsid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.BSSID = VALID_BSSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -115,7 +116,7 @@
 
     @Test
     public void createFromScanResult_emptySsid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = "";
         scanResult.BSSID = VALID_BSSID;
 
@@ -124,7 +125,7 @@
 
     @Test
     public void createFromScanResult_noneSsid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = WifiManager.UNKNOWN_SSID;
         scanResult.BSSID = VALID_BSSID;
 
@@ -133,7 +134,7 @@
 
     @Test
     public void createFromScanResult_nullBssid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = VALID_UNQUOTED_SSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -141,7 +142,7 @@
 
     @Test
     public void createFromScanResult_emptyBssid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = "";
 
@@ -150,7 +151,7 @@
 
     @Test
     public void createFromScanResult_invalidBssid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = INVALID_BSSID;
 
@@ -159,7 +160,7 @@
 
     @Test
     public void createFromScanResult_validSsid() {
-        ScanResult scanResult = new ScanResult();
+        ScanResult scanResult = mock(ScanResult.class);
         scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = VALID_BSSID;
 
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index ea66ee3..70d4678 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1 +1 @@
-per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com
+per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com, lorenzo@google.com
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index d945fc4..a7f8cc4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -215,6 +215,7 @@
         android: {
 
             srcs: [
+                "pipeline/skia/ATraceMemoryDump.cpp",
                 "pipeline/skia/GLFunctorDrawable.cpp",
                 "pipeline/skia/LayerDrawable.cpp",
                 "pipeline/skia/ShaderCache.cpp",
@@ -244,7 +245,6 @@
                 "DeviceInfo.cpp",
                 "FrameInfo.cpp",
                 "FrameInfoVisualizer.cpp",
-                "GpuMemoryTracker.cpp",
                 "HardwareBitmapUploader.cpp",
                 "HWUIProperties.sysprop",
                 "JankTracker.cpp",
@@ -325,7 +325,6 @@
         "tests/unit/DamageAccumulatorTests.cpp",
         "tests/unit/DeferredLayerUpdaterTests.cpp",
         "tests/unit/FatVectorTests.cpp",
-        "tests/unit/GpuMemoryTrackerTests.cpp",
         "tests/unit/GraphicsStatsServiceTests.cpp",
         "tests/unit/LayerUpdateQueueTests.cpp",
         "tests/unit/LinearAllocatorTests.cpp",
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
deleted file mode 100644
index a9a7af8..0000000
--- a/libs/hwui/GpuMemoryTracker.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utils/StringUtils.h"
-
-#include <GpuMemoryTracker.h>
-#include <cutils/compiler.h>
-#include <utils/Trace.h>
-#include <array>
-#include <sstream>
-#include <unordered_set>
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-pthread_t gGpuThread = 0;
-
-#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
-
-const char* TYPE_NAMES[] = {
-        "Texture", "OffscreenBuffer", "Layer",
-};
-
-struct TypeStats {
-    int totalSize = 0;
-    int count = 0;
-};
-
-static std::array<TypeStats, NUM_TYPES> gObjectStats;
-static std::unordered_set<GpuMemoryTracker*> gObjectSet;
-
-void GpuMemoryTracker::notifySizeChanged(int newSize) {
-    int delta = newSize - mSize;
-    mSize = newSize;
-    gObjectStats[static_cast<int>(mType)].totalSize += delta;
-}
-
-void GpuMemoryTracker::startTrackingObject() {
-    auto result = gObjectSet.insert(this);
-    LOG_ALWAYS_FATAL_IF(!result.second,
-                        "startTrackingObject() on %p failed, already being tracked!", this);
-    gObjectStats[static_cast<int>(mType)].count++;
-}
-
-void GpuMemoryTracker::stopTrackingObject() {
-    size_t removed = gObjectSet.erase(this);
-    LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
-                        removed, this);
-    gObjectStats[static_cast<int>(mType)].count--;
-}
-
-void GpuMemoryTracker::onGpuContextCreated() {
-    LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
-                        "We already have a gpu thread? "
-                        "current = %lu, gpu thread = %lu",
-                        pthread_self(), gGpuThread);
-    gGpuThread = pthread_self();
-}
-
-void GpuMemoryTracker::onGpuContextDestroyed() {
-    gGpuThread = 0;
-    if (CC_UNLIKELY(gObjectSet.size() > 0)) {
-        std::stringstream os;
-        dump(os);
-        ALOGE("%s", os.str().c_str());
-        LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
-    }
-}
-
-void GpuMemoryTracker::dump() {
-    std::stringstream strout;
-    dump(strout);
-    ALOGD("%s", strout.str().c_str());
-}
-
-void GpuMemoryTracker::dump(std::ostream& stream) {
-    for (int type = 0; type < NUM_TYPES; type++) {
-        const TypeStats& stats = gObjectStats[type];
-        stream << TYPE_NAMES[type];
-        stream << " is using " << SizePrinter{stats.totalSize};
-        stream << ", count = " << stats.count;
-        stream << std::endl;
-    }
-}
-
-int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
-    return gObjectStats[static_cast<int>(type)].count;
-}
-
-int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
-    return gObjectStats[static_cast<int>(type)].totalSize;
-}
-
-void GpuMemoryTracker::onFrameCompleted() {
-    if (ATRACE_ENABLED()) {
-        char buf[128];
-        for (int type = 0; type < NUM_TYPES; type++) {
-            snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
-            const TypeStats& stats = gObjectStats[type];
-            ATRACE_INT(buf, stats.totalSize);
-            snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
-            ATRACE_INT(buf, stats.count);
-        }
-    }
-}
-
-}  // namespace uirenderer
-}  // namespace android;
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
deleted file mode 100644
index de3ca99..0000000
--- a/libs/hwui/GpuMemoryTracker.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <pthread.h>
-#include <ostream>
-
-#include <log/log.h>
-
-namespace android {
-namespace uirenderer {
-
-extern pthread_t gGpuThread;
-
-#define ASSERT_GPU_THREAD()                                                                    \
-    LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()),                            \
-                        "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
-                        "!= gpu thread %lu",                                                   \
-                        this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread)
-
-enum class GpuObjectType {
-    Texture = 0,
-    OffscreenBuffer,
-    Layer,
-
-    TypeCount,
-};
-
-class GpuMemoryTracker {
-public:
-    GpuObjectType objectType() { return mType; }
-    int objectSize() { return mSize; }
-
-    static void onGpuContextCreated();
-    static void onGpuContextDestroyed();
-    static void dump();
-    static void dump(std::ostream& stream);
-    static int getInstanceCount(GpuObjectType type);
-    static int getTotalSize(GpuObjectType type);
-    static void onFrameCompleted();
-
-protected:
-    explicit GpuMemoryTracker(GpuObjectType type) : mType(type) {
-        ASSERT_GPU_THREAD();
-        startTrackingObject();
-    }
-
-    ~GpuMemoryTracker() {
-        notifySizeChanged(0);
-        stopTrackingObject();
-    }
-
-    void notifySizeChanged(int newSize);
-
-private:
-    void startTrackingObject();
-    void stopTrackingObject();
-
-    int mSize = 0;
-    GpuObjectType mType;
-};
-
-}  // namespace uirenderer
-}  // namespace android;
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
new file mode 100644
index 0000000..2c78b02
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ATraceMemoryDump.h"
+
+#include <utils/Trace.h>
+
+#include <cstring>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+// When purgeable is INVALID_TIME it won't be logged at all.
+#define INVALID_TIME -1
+
+/**
+ * Skia invokes the following SkTraceMemoryDump functions:
+ * 1. dumpNumericValue (dumpName, units="bytes", valueName="size")
+ * 2. dumpStringValue (dumpName, valueName="type") [optional -> for example CPU memory does not
+ * invoke dumpStringValue]
+ * 3. dumpNumericValue (dumpName, units="bytes", valueName="purgeable_size") [optional]
+ * 4. setMemoryBacking(dumpName, backingType) [optional -> for example Vulkan GPU resources do not
+ * invoke setMemoryBacking]
+ *
+ * ATraceMemoryDump calculates memory category first by looking at the "type" string passed to
+ * dumpStringValue and then by looking at "backingType" passed to setMemoryBacking.
+ * Only GPU Texture memory is tracked separately and everything else is grouped as one
+ * "GPU Memory" category.
+ */
+static std::unordered_map<const char*, const char*> sResourceMap = {
+        {"malloc", "Graphics CPU Memory"},          // taken from setMemoryBacking(backingType)
+        {"gl_texture", "Graphics Texture Memory"},  // taken from setMemoryBacking(backingType)
+        {"Texture",
+         "Graphics Texture Memory"},  // taken from dumpStringValue(value, valueName="type")
+        // Uncomment categories below to split "GPU Memory" into more brackets for debugging.
+        /*{"vk_buffer", "vk_buffer"},
+        {"gl_renderbuffer", "gl_renderbuffer"},
+        {"gl_buffer", "gl_buffer"},
+        {"RenderTarget", "RenderTarget"},
+        {"Stencil", "Stencil"},
+        {"Path Data", "Path Data"},
+        {"Buffer Object", "Buffer Object"},
+        {"Surface", "Surface"},*/
+};
+
+ATraceMemoryDump::ATraceMemoryDump() {
+    mLastDumpName.reserve(100);
+    mCategory.reserve(100);
+}
+
+void ATraceMemoryDump::dumpNumericValue(const char* dumpName, const char* valueName,
+                                        const char* units, uint64_t value) {
+    if (!strcmp(units, "bytes")) {
+        recordAndResetCountersIfNeeded(dumpName);
+        if (!strcmp(valueName, "size")) {
+            mLastDumpValue = value;
+        } else if (!strcmp(valueName, "purgeable_size")) {
+            mLastPurgeableDumpValue = value;
+        }
+    }
+}
+
+void ATraceMemoryDump::dumpStringValue(const char* dumpName, const char* valueName,
+                                       const char* value) {
+    if (!strcmp(valueName, "type")) {
+        recordAndResetCountersIfNeeded(dumpName);
+        auto categoryIt = sResourceMap.find(value);
+        if (categoryIt != sResourceMap.end()) {
+            mCategory = categoryIt->second;
+        }
+    }
+}
+
+void ATraceMemoryDump::setMemoryBacking(const char* dumpName, const char* backingType,
+                                        const char* backingObjectId) {
+    recordAndResetCountersIfNeeded(dumpName);
+    auto categoryIt = sResourceMap.find(backingType);
+    if (categoryIt != sResourceMap.end()) {
+        mCategory = categoryIt->second;
+    }
+}
+
+/**
+ * startFrame is invoked before dumping anything. It resets counters from the previous frame.
+ * This is important, because if there is no new data for a given category trace would assume
+ * usage has not changed (instead of reporting 0).
+ */
+void ATraceMemoryDump::startFrame() {
+    resetCurrentCounter("");
+    for (auto& it : mCurrentValues) {
+        // Once a category is observed in at least one frame, it is always reported in subsequent
+        // frames (even if it is 0). Not logging a category to ATRACE would mean its value has not
+        // changed since the previous frame, which is not what we want.
+        it.second.time = 0;
+        // If purgeableTime is INVALID_TIME, then logTraces won't log it at all.
+        if (it.second.purgeableTime != INVALID_TIME) {
+            it.second.purgeableTime = 0;
+        }
+    }
+}
+
+/**
+ * logTraces reads from mCurrentValues and logs the counters with ATRACE.
+ */
+void ATraceMemoryDump::logTraces() {
+    // Accumulate data from last dumpName
+    recordAndResetCountersIfNeeded("");
+    for (auto& it : mCurrentValues) {
+        ATRACE_INT64(it.first.c_str(), it.second.time);
+        if (it.second.purgeableTime != INVALID_TIME) {
+            ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableTime);
+        }
+    }
+}
+
+/**
+ * recordAndResetCountersIfNeeded reads memory usage from mLastDumpValue/mLastPurgeableDumpValue and
+ * accumulates in mCurrentValues[category]. It makes provision to create a new category and track
+ * purgeable memory only if there is at least one observation.
+ * recordAndResetCountersIfNeeded won't do anything until all the information for a given dumpName
+ * is received.
+ */
+void ATraceMemoryDump::recordAndResetCountersIfNeeded(const char* dumpName) {
+    if (!mLastDumpName.compare(dumpName)) {
+        // Still waiting for more data for current dumpName.
+        return;
+    }
+
+    // First invocation will have an empty mLastDumpName.
+    if (!mLastDumpName.empty()) {
+        // A new dumpName observed -> store the data already collected.
+        auto memoryCounter = mCurrentValues.find(mCategory);
+        if (memoryCounter != mCurrentValues.end()) {
+            memoryCounter->second.time += mLastDumpValue;
+            if (mLastPurgeableDumpValue != INVALID_TIME) {
+                if (memoryCounter->second.purgeableTime == INVALID_TIME) {
+                    memoryCounter->second.purgeableTime = mLastPurgeableDumpValue;
+                } else {
+                    memoryCounter->second.purgeableTime += mLastPurgeableDumpValue;
+                }
+            }
+        } else {
+            mCurrentValues[mCategory] = {mLastDumpValue, mLastPurgeableDumpValue};
+        }
+    }
+
+    // Reset counters and default category for the newly observed "dumpName".
+    resetCurrentCounter(dumpName);
+}
+
+void ATraceMemoryDump::resetCurrentCounter(const char* dumpName) {
+    mLastDumpValue = 0;
+    mLastPurgeableDumpValue = INVALID_TIME;
+    mLastDumpName = dumpName;
+    // Categories not listed in sResourceMap are reported as "GPU memory"
+    mCategory = "GPU Memory";
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.h b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
new file mode 100644
index 0000000..aa5c401
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <SkString.h>
+#include <SkTraceMemoryDump.h>
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class ATraceMemoryDump : public SkTraceMemoryDump {
+public:
+    ATraceMemoryDump();
+    ~ATraceMemoryDump() override {}
+
+    void dumpNumericValue(const char* dumpName, const char* valueName, const char* units,
+                          uint64_t value) override;
+
+    void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override;
+
+    LevelOfDetail getRequestedDetails() const override {
+        return SkTraceMemoryDump::kLight_LevelOfDetail;
+    }
+
+    bool shouldDumpWrappedObjects() const override { return false; }
+
+    void setMemoryBacking(const char* dumpName, const char* backingType,
+                          const char* backingObjectId) override;
+
+    void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {}
+
+    void startFrame();
+
+    void logTraces();
+
+private:
+    std::string mLastDumpName;
+
+    uint64_t mLastDumpValue;
+
+    uint64_t mLastPurgeableDumpValue;
+
+    std::string mCategory;
+
+    struct TraceValue {
+        uint64_t time;
+        uint64_t purgeableTime;
+    };
+
+    // keys are define in sResourceMap
+    std::unordered_map<std::string, TraceValue> mCurrentValues;
+
+    void recordAndResetCountersIfNeeded(const char* dumpName);
+
+    void resetCurrentCounter(const char* dumpName);
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
\ No newline at end of file
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index fad9440..7e8c96d 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -16,7 +16,6 @@
 #include "renderstate/RenderState.h"
 
 #include "renderthread/RenderThread.h"
-#include "GpuMemoryTracker.h"
 
 namespace android {
 namespace uirenderer {
@@ -25,15 +24,10 @@
     mThreadId = pthread_self();
 }
 
-void RenderState::onContextCreated() {
-    GpuMemoryTracker::onGpuContextCreated();
-}
-
 void RenderState::onContextDestroyed() {
     for(auto callback : mContextCallbacks) {
         callback->onContextDestroyed();
     }
-    GpuMemoryTracker::onGpuContextDestroyed();
 }
 
 void RenderState::postDecStrong(VirtualLightRefBase* object) {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index ff5d02f..e08d32a 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -62,7 +62,6 @@
     ~RenderState() {}
 
     // Context notifications are only to be triggered by renderthread::RenderThread
-    void onContextCreated();
     void onContextDestroyed();
 
     std::set<IGpuContextCallback*> mContextCallbacks;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index eaed46c..d177855 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -20,10 +20,12 @@
 #include "Layer.h"
 #include "Properties.h"
 #include "RenderThread.h"
+#include "pipeline/skia/ATraceMemoryDump.h"
 #include "pipeline/skia/ShaderCache.h"
 #include "pipeline/skia/SkiaMemoryTracer.h"
 #include "renderstate/RenderState.h"
 #include "thread/CommonPool.h"
+#include <utils/Trace.h>
 
 #include <GrContextOptions.h>
 #include <SkExecutor.h>
@@ -184,6 +186,18 @@
     gpuTracer.logTotals(log);
 }
 
+void CacheManager::onFrameCompleted() {
+    if (ATRACE_ENABLED()) {
+        static skiapipeline::ATraceMemoryDump tracer;
+        tracer.startFrame();
+        SkGraphics::DumpMemoryStatistics(&tracer);
+        if (mGrContext) {
+            mGrContext->dumpMemoryStatistics(&tracer);
+        }
+        tracer.logTraces();
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 968251e..b009cc4 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -50,6 +50,7 @@
 
     size_t getCacheSize() const { return mMaxResourceBytes; }
     size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
+    void onFrameCompleted();
 
 private:
     friend class RenderThread;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8490221..5993e17 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -16,7 +16,6 @@
 
 #include "CanvasContext.h"
 
-#include <GpuMemoryTracker.h>
 #include <apex/window.h>
 #include <fcntl.h>
 #include <strings.h>
@@ -558,7 +557,7 @@
         mJankTracker.finishGpuDraw(*forthBehind);
     }
 
-    GpuMemoryTracker::onFrameCompleted();
+    mRenderThread.cacheManager().onFrameCompleted();
 }
 
 // Called by choreographer to do an RT-driven animation
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index d78f641..cae3e3b 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -270,7 +270,6 @@
     }
     mGrContext = std::move(context);
     if (mGrContext) {
-        mRenderState->onContextCreated();
         DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
     }
 }
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
deleted file mode 100644
index dac888c..0000000
--- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <GpuMemoryTracker.h>
-#include <gtest/gtest.h>
-
-#include "renderthread/EglManager.h"
-#include "renderthread/RenderThread.h"
-#include "tests/common/TestUtils.h"
-
-#include <utils/StrongPointer.h>
-
-using namespace android;
-using namespace android::uirenderer;
-using namespace android::uirenderer::renderthread;
-
-class TestGPUObject : public GpuMemoryTracker {
-public:
-    TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {}
-
-    void changeSize(int newSize) { notifySizeChanged(newSize); }
-};
-
-// Other tests may have created a renderthread and EGL context.
-// This will destroy the EGLContext on RenderThread if it exists so that the
-// current thread can spoof being a GPU thread
-static void destroyEglContext() {
-    if (TestUtils::isRenderThreadRunning()) {
-        TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyRenderingContext(); });
-    }
-}
-
-TEST(GpuMemoryTracker, sizeCheck) {
-    destroyEglContext();
-
-    GpuMemoryTracker::onGpuContextCreated();
-    ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
-    ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
-    {
-        TestGPUObject myObj;
-        ASSERT_EQ(1, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
-        myObj.changeSize(500);
-        ASSERT_EQ(500, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
-        myObj.changeSize(1000);
-        ASSERT_EQ(1000, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
-        myObj.changeSize(300);
-        ASSERT_EQ(300, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
-    }
-    ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
-    ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
-    GpuMemoryTracker::onGpuContextDestroyed();
-}
diff --git a/media/java/android/media/tv/tuner/DemuxCapabilities.java b/media/java/android/media/tv/tuner/DemuxCapabilities.java
index bda166e..83abf86 100644
--- a/media/java/android/media/tv/tuner/DemuxCapabilities.java
+++ b/media/java/android/media/tv/tuner/DemuxCapabilities.java
@@ -16,11 +16,32 @@
 
 package android.media.tv.tuner;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.Size;
+import android.media.tv.tuner.filter.FilterConfiguration;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Capabilities info for Demux.
+ *
  * @hide
  */
 public class DemuxCapabilities {
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            FilterConfiguration.FILTER_TYPE_TS,
+            FilterConfiguration.FILTER_TYPE_MMTP,
+            FilterConfiguration.FILTER_TYPE_IP,
+            FilterConfiguration.FILTER_TYPE_TLV,
+            FilterConfiguration.FILTER_TYPE_ALP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FilterCapabilities {}
+
     private final int mNumDemux;
     private final int mNumRecord;
     private final int mNumPlayback;
@@ -34,7 +55,8 @@
     private final int mFilterCaps;
     private final int[] mLinkCaps;
 
-    DemuxCapabilities(int numDemux, int numRecord, int numPlayback, int numTsFilter,
+    // Used by JNI
+    private DemuxCapabilities(int numDemux, int numRecord, int numPlayback, int numTsFilter,
             int numSectionFilter, int numAudioFilter, int numVideoFilter, int numPesFilter,
             int numPcrFilter, int numBytesInSectionFilter, int filterCaps, int[] linkCaps) {
         mNumDemux = numDemux;
@@ -51,52 +73,73 @@
         mLinkCaps = linkCaps;
     }
 
-    /** Gets total number of demuxes. */
+    /**
+     * Gets total number of demuxes.
+     */
     public int getNumDemux() {
         return mNumDemux;
     }
-    /** Gets max number of recordings at a time. */
+    /**
+     * Gets max number of recordings at a time.
+     */
     public int getNumRecord() {
         return mNumRecord;
     }
-    /** Gets max number of playbacks at a time. */
+    /**
+     * Gets max number of playbacks at a time.
+     */
     public int getNumPlayback() {
         return mNumPlayback;
     }
-    /** Gets number of TS filters. */
+    /**
+     * Gets number of TS filters.
+     */
     public int getNumTsFilter() {
         return mNumTsFilter;
     }
-    /** Gets number of section filters. */
+    /**
+     * Gets number of section filters.
+     */
     public int getNumSectionFilter() {
         return mNumSectionFilter;
     }
-    /** Gets number of audio filters. */
+    /**
+     * Gets number of audio filters.
+     */
     public int getNumAudioFilter() {
         return mNumAudioFilter;
     }
-    /** Gets number of video filters. */
+    /**
+     * Gets number of video filters.
+     */
     public int getNumVideoFilter() {
         return mNumVideoFilter;
     }
-    /** Gets number of PES filters. */
+    /**
+     * Gets number of PES filters.
+     */
     public int getNumPesFilter() {
         return mNumPesFilter;
     }
-    /** Gets number of PCR filters. */
+    /**
+     * Gets number of PCR filters.
+     */
     public int getNumPcrFilter() {
         return mNumPcrFilter;
     }
-    /** Gets number of bytes in the mask of a section filter. */
+    /**
+     * Gets number of bytes in the mask of a section filter.
+     */
     public int getNumBytesInSectionFilter() {
         return mNumBytesInSectionFilter;
     }
     /**
      * Gets filter capabilities in bit field.
      *
-     * The bits of the returned value is corresponding to the types in
-     * {@link TunerConstants.FilterType}.
+     * <p>The bits of the returned value is corresponding to the types in
+     * {@link FilterConfiguration}.
      */
+    @FilterCapabilities
     public int getFilterCapabilities() {
         return mFilterCaps;
     }
@@ -104,10 +147,12 @@
     /**
      * Gets link capabilities.
      *
-     * The returned array contains the same elements as the number of types in
-     * {@link TunerConstants.FilterType}.
-     * The ith element represents the filter's capability as the source for the ith type
+     * <p>The returned array contains the same elements as the number of types in
+     * {@link FilterConfiguration}.
+     * <p>The ith element represents the filter's capability as the source for the ith type.
      */
+    @Nullable
+    @Size(5)
     public int[] getLinkCapabilities() {
         return mLinkCaps;
     }
diff --git a/media/java/android/media/tv/tuner/FrontendSettings.java b/media/java/android/media/tv/tuner/FrontendSettings.java
index e2e9910..ad8422c 100644
--- a/media/java/android/media/tv/tuner/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/FrontendSettings.java
@@ -17,7 +17,6 @@
 package android.media.tv.tuner;
 
 import android.annotation.SystemApi;
-import android.media.tv.tuner.TunerConstants.FrontendSettingsType;
 
 /**
  * Frontend settings for tune and scan operations.
@@ -35,7 +34,6 @@
     /**
      * Returns the frontend type.
      */
-    @FrontendSettingsType
     public abstract int getType();
 
     /**
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
new file mode 100644
index 0000000..f181b49
--- /dev/null
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner.LnbCallback;
+import android.media.tv.tuner.TunerConstants.Result;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * LNB (low-noise block downconverter) for satellite tuner.
+ *
+ * A Tuner LNB (low-noise block downconverter) is used by satellite frontend to receive the
+ * microwave signal from the satellite, amplify it, and downconvert the frequency to a lower
+ * frequency.
+ *
+ * @hide
+ */
+public class Lnb implements AutoCloseable {
+    /** @hide */
+    @IntDef({VOLTAGE_NONE, VOLTAGE_5V, VOLTAGE_11V, VOLTAGE_12V, VOLTAGE_13V, VOLTAGE_14V,
+            VOLTAGE_15V, VOLTAGE_18V, VOLTAGE_19V})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Voltage {}
+
+    /**
+     * LNB power voltage not set.
+     */
+    public static final int VOLTAGE_NONE = Constants.LnbVoltage.NONE;
+    /**
+     * LNB power voltage 5V.
+     */
+    public static final int VOLTAGE_5V = Constants.LnbVoltage.VOLTAGE_5V;
+    /**
+     * LNB power voltage 11V.
+     */
+    public static final int VOLTAGE_11V = Constants.LnbVoltage.VOLTAGE_11V;
+    /**
+     * LNB power voltage 12V.
+     */
+    public static final int VOLTAGE_12V = Constants.LnbVoltage.VOLTAGE_12V;
+    /**
+     * LNB power voltage 13V.
+     */
+    public static final int VOLTAGE_13V = Constants.LnbVoltage.VOLTAGE_13V;
+    /**
+     * LNB power voltage 14V.
+     */
+    public static final int VOLTAGE_14V = Constants.LnbVoltage.VOLTAGE_14V;
+    /**
+     * LNB power voltage 15V.
+     */
+    public static final int VOLTAGE_15V = Constants.LnbVoltage.VOLTAGE_15V;
+    /**
+     * LNB power voltage 18V.
+     */
+    public static final int VOLTAGE_18V = Constants.LnbVoltage.VOLTAGE_18V;
+    /**
+     * LNB power voltage 19V.
+     */
+    public static final int VOLTAGE_19V = Constants.LnbVoltage.VOLTAGE_19V;
+
+    /** @hide */
+    @IntDef({TONE_NONE, TONE_CONTINUOUS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Tone {}
+
+    /**
+     * LNB tone mode not set.
+     */
+    public static final int TONE_NONE = Constants.LnbTone.NONE;
+    /**
+     * LNB continuous tone mode.
+     */
+    public static final int TONE_CONTINUOUS = Constants.LnbTone.CONTINUOUS;
+
+    /** @hide */
+    @IntDef({POSITION_UNDEFINED, POSITION_A, POSITION_B})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Position {}
+
+    /**
+     * LNB position is not defined.
+     */
+    public static final int POSITION_UNDEFINED = Constants.LnbPosition.UNDEFINED;
+    /**
+     * Position A of two-band LNBs
+     */
+    public static final int POSITION_A = Constants.LnbPosition.POSITION_A;
+    /**
+     * Position B of two-band LNBs
+     */
+    public static final int POSITION_B = Constants.LnbPosition.POSITION_B;
+
+    int mId;
+    LnbCallback mCallback;
+    Context mContext;
+
+    private native int nativeSetVoltage(int voltage);
+    private native int nativeSetTone(int tone);
+    private native int nativeSetSatellitePosition(int position);
+    private native int nativeSendDiseqcMessage(byte[] message);
+    private native int nativeClose();
+
+    Lnb(int id) {
+        mId = id;
+    }
+
+    /** @hide */
+    public void setCallback(@Nullable LnbCallback callback) {
+        mCallback = callback;
+        if (mCallback == null) {
+            return;
+        }
+    }
+
+    /**
+     * Sets the LNB's power voltage.
+     *
+     * @param voltage the power voltage constant the Lnb to use.
+     * @return result status of the operation.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
+    public int setVoltage(@Voltage int voltage) {
+        TunerUtils.checkTunerPermission(mContext);
+        return nativeSetVoltage(voltage);
+    }
+
+    /**
+     * Sets the LNB's tone mode.
+     *
+     * @param tone the tone mode the Lnb to use.
+     * @return result status of the operation.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
+    public int setTone(@Tone int tone) {
+        TunerUtils.checkTunerPermission(mContext);
+        return nativeSetTone(tone);
+    }
+
+    /**
+     * Selects the LNB's position.
+     *
+     * @param position the position the Lnb to use.
+     * @return result status of the operation.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
+    public int setSatellitePosition(@Position int position) {
+        TunerUtils.checkTunerPermission(mContext);
+        return nativeSetSatellitePosition(position);
+    }
+
+    /**
+     * Sends DiSEqC (Digital Satellite Equipment Control) message.
+     *
+     * The response message from the device comes back through callback onDiseqcMessage.
+     *
+     * @param message a byte array of data for DiSEqC message which is specified by EUTELSAT Bus
+     *         Functional Specification Version 4.2.
+     *
+     * @return result status of the operation.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Result
+    public int sendDiseqcMessage(@NonNull byte[] message) {
+        TunerUtils.checkTunerPermission(mContext);
+        return nativeSendDiseqcMessage(message);
+    }
+
+    /**
+     * Releases the LNB instance.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    public void close() {
+        TunerUtils.checkTunerPermission(mContext);
+        nativeClose();
+    }
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 962a7f6..1424c33 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -24,9 +24,6 @@
 import android.media.tv.tuner.TunerConstants.FilterStatus;
 import android.media.tv.tuner.TunerConstants.FilterSubtype;
 import android.media.tv.tuner.TunerConstants.FrontendScanType;
-import android.media.tv.tuner.TunerConstants.LnbPosition;
-import android.media.tv.tuner.TunerConstants.LnbTone;
-import android.media.tv.tuner.TunerConstants.LnbVoltage;
 import android.media.tv.tuner.TunerConstants.Result;
 import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 import android.media.tv.tuner.filter.FilterEvent;
@@ -219,11 +216,6 @@
                     }
                     break;
                 }
-                case MSG_ON_LNB_EVENT: {
-                    if (mLnb != null && mLnb.mCallback != null) {
-                        mLnb.mCallback.onEvent(msg.arg1);
-                    }
-                }
                 default:
                     // fall through
             }
@@ -423,8 +415,14 @@
         return mFrontend.mId;
     }
 
-    /** @hide */
-    private static DemuxCapabilities getDemuxCapabilities() {
+    /**
+     * Gets Demux capabilities.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+    @Nullable
+    public static DemuxCapabilities getDemuxCapabilities(@NonNull Context context) {
+        TunerUtils.checkTunerPermission(context);
         return nativeGetDemuxCapabilities();
     }
 
@@ -474,102 +472,6 @@
         return filter;
     }
 
-    /**
-     * Open a time filter instance.
-     *
-     * It is used to open time filter of demux.
-     *
-     * @return a time filter instance.
-     * @hide
-     */
-    public TimeFilter openTimeFilter() {
-        return nativeOpenTimeFilter();
-    }
-
-    /** @hide */
-    public class Lnb {
-        private int mId;
-        private LnbCallback mCallback;
-
-        private native int nativeSetVoltage(int voltage);
-        private native int nativeSetTone(int tone);
-        private native int nativeSetSatellitePosition(int position);
-        private native int nativeSendDiseqcMessage(byte[] message);
-        private native int nativeClose();
-
-        private Lnb(int id) {
-            mId = id;
-        }
-
-        public void setCallback(@Nullable LnbCallback callback) {
-            mCallback = callback;
-            if (mCallback == null) {
-                return;
-            }
-            if (mHandler == null) {
-                mHandler = createEventHandler();
-            }
-        }
-
-        /**
-         * Sets the LNB's power voltage.
-         *
-         * @param voltage the power voltage the Lnb to use.
-         * @return result status of the operation.
-         */
-        @Result
-        public int setVoltage(@LnbVoltage int voltage) {
-            return nativeSetVoltage(voltage);
-        }
-
-        /**
-         * Sets the LNB's tone mode.
-         *
-         * @param tone the tone mode the Lnb to use.
-         * @return result status of the operation.
-         */
-        @Result
-        public int setTone(@LnbTone int tone) {
-            return nativeSetTone(tone);
-        }
-
-        /**
-         * Selects the LNB's position.
-         *
-         * @param position the position the Lnb to use.
-         * @return result status of the operation.
-         */
-        @Result
-        public int setSatellitePosition(@LnbPosition int position) {
-            return nativeSetSatellitePosition(position);
-        }
-
-        /**
-         * Sends DiSEqC (Digital Satellite Equipment Control) message.
-         *
-         * The response message from the device comes back through callback onDiseqcMessage.
-         *
-         * @param message a byte array of data for DiSEqC message which is specified by EUTELSAT Bus
-         *         Functional Specification Version 4.2.
-         *
-         * @return result status of the operation.
-         */
-        @Result
-        public int sendDiseqcMessage(byte[] message) {
-            return nativeSendDiseqcMessage(message);
-        }
-
-        /**
-         * Releases the LNB instance
-         *
-         * @return result status of the operation.
-         */
-        @Result
-        public int close() {
-            return nativeClose();
-        }
-    }
-
     private List<Integer> getLnbIds() {
         mLnbIds = nativeGetLnbIds();
         return mLnbIds;
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index bbaa518..a55c485 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -38,35 +38,6 @@
 
 
     /** @hide */
-    @IntDef({FRONTEND_TYPE_UNDEFINED, FRONTEND_TYPE_ANALOG, FRONTEND_TYPE_ATSC, FRONTEND_TYPE_ATSC3,
-            FRONTEND_TYPE_DVBC, FRONTEND_TYPE_DVBS, FRONTEND_TYPE_DVBT, FRONTEND_TYPE_ISDBS,
-            FRONTEND_TYPE_ISDBS3, FRONTEND_TYPE_ISDBT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FrontendType {}
-
-    /** @hide */
-    public static final int FRONTEND_TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ANALOG = Constants.FrontendType.ANALOG;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ATSC = Constants.FrontendType.ATSC;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ATSC3 = Constants.FrontendType.ATSC3;
-    /** @hide */
-    public static final int FRONTEND_TYPE_DVBC = Constants.FrontendType.DVBC;
-    /** @hide */
-    public static final int FRONTEND_TYPE_DVBS = Constants.FrontendType.DVBS;
-    /** @hide */
-    public static final int FRONTEND_TYPE_DVBT = Constants.FrontendType.DVBT;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ISDBS = Constants.FrontendType.ISDBS;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ISDBS3 = Constants.FrontendType.ISDBS3;
-    /** @hide */
-    public static final int FRONTEND_TYPE_ISDBT = Constants.FrontendType.ISDBT;
-
-
-    /** @hide */
     @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL,
             FRONTEND_EVENT_TYPE_LOST_LOCK})
     @Retention(RetentionPolicy.SOURCE)
@@ -102,30 +73,6 @@
     /** @hide */
     public static final int DEMUX_MMPT_PID = 2;
 
-    /** @hide */
-    @IntDef({FRONTEND_SETTINGS_ANALOG, FRONTEND_SETTINGS_ATSC, FRONTEND_SETTINGS_ATSC3,
-            FRONTEND_SETTINGS_DVBS, FRONTEND_SETTINGS_DVBC, FRONTEND_SETTINGS_DVBT,
-            FRONTEND_SETTINGS_ISDBS, FRONTEND_SETTINGS_ISDBS3, FRONTEND_SETTINGS_ISDBT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FrontendSettingsType {}
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ANALOG = 1;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ATSC = 2;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ATSC3 = 3;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_DVBS = 4;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_DVBC = 5;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_DVBT = 6;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ISDBS = 7;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ISDBS3 = 8;
-    /** @hide */
-    public static final int FRONTEND_SETTINGS_ISDBT = 9;
 
     /** @hide */
     @IntDef({FILTER_SUBTYPE_UNDEFINED, FILTER_SUBTYPE_SECTION, FILTER_SUBTYPE_PES,
@@ -727,73 +674,6 @@
             Constants.FrontendDvbtHierarchy.HIERARCHY_4_INDEPTH;
 
     /** @hide */
-    @IntDef({FRONTEND_ANALOG_TYPE_UNDEFINED, FRONTEND_ANALOG_TYPE_PAL, FRONTEND_ANALOG_TYPE_SECAM,
-            FRONTEND_ANALOG_TYPE_NTSC})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FrontendAnalogType {}
-    /** @hide */
-    public static final int FRONTEND_ANALOG_TYPE_UNDEFINED = Constants.FrontendAnalogType.UNDEFINED;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_TYPE_PAL = Constants.FrontendAnalogType.PAL;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_TYPE_SECAM = Constants.FrontendAnalogType.SECAM;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_TYPE_NTSC = Constants.FrontendAnalogType.NTSC;
-
-    /** @hide */
-    @IntDef({FRONTEND_ANALOG_SIF_UNDEFINED, FRONTEND_ANALOG_SIF_BG, FRONTEND_ANALOG_SIF_BG_A2,
-            FRONTEND_ANALOG_SIF_BG_NICAM, FRONTEND_ANALOG_SIF_I, FRONTEND_ANALOG_SIF_DK,
-            FRONTEND_ANALOG_SIF_DK1, FRONTEND_ANALOG_SIF_DK2, FRONTEND_ANALOG_SIF_DK3,
-            FRONTEND_ANALOG_SIF_DK_NICAM, FRONTEND_ANALOG_SIF_L, FRONTEND_ANALOG_SIF_M,
-            FRONTEND_ANALOG_SIF_M_BTSC, FRONTEND_ANALOG_SIF_M_A2, FRONTEND_ANALOG_SIF_M_EIA_J,
-            FRONTEND_ANALOG_SIF_I_NICAM, FRONTEND_ANALOG_SIF_L_NICAM, FRONTEND_ANALOG_SIF_L_PRIME})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FrontendAnalogSifStandard {}
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_UNDEFINED =
-            Constants.FrontendAnalogSifStandard.UNDEFINED;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_BG = Constants.FrontendAnalogSifStandard.BG;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_BG_A2 = Constants.FrontendAnalogSifStandard.BG_A2;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_BG_NICAM =
-            Constants.FrontendAnalogSifStandard.BG_NICAM;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_I = Constants.FrontendAnalogSifStandard.I;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_DK = Constants.FrontendAnalogSifStandard.DK;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_DK1 = Constants.FrontendAnalogSifStandard.DK1;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_DK2 = Constants.FrontendAnalogSifStandard.DK2;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_DK3 = Constants.FrontendAnalogSifStandard.DK3;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_DK_NICAM =
-            Constants.FrontendAnalogSifStandard.DK_NICAM;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_L = Constants.FrontendAnalogSifStandard.L;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_M = Constants.FrontendAnalogSifStandard.M;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_M_BTSC = Constants.FrontendAnalogSifStandard.M_BTSC;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_M_A2 = Constants.FrontendAnalogSifStandard.M_A2;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_M_EIA_J =
-            Constants.FrontendAnalogSifStandard.M_EIA_J;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_I_NICAM =
-            Constants.FrontendAnalogSifStandard.I_NICAM;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_L_NICAM =
-            Constants.FrontendAnalogSifStandard.L_NICAM;
-    /** @hide */
-    public static final int FRONTEND_ANALOG_SIF_L_PRIME =
-            Constants.FrontendAnalogSifStandard.L_PRIME;
-
-    /** @hide */
     @IntDef({FRONTEND_ATSC_MODULATION_UNDEFINED, FRONTEND_ATSC_MODULATION_AUTO,
             FRONTEND_ATSC_MODULATION_MOD_8VSB, FRONTEND_ATSC_MODULATION_MOD_16VSB})
     @Retention(RetentionPolicy.SOURCE)
@@ -1263,68 +1143,45 @@
 
 
     /** @hide */
-    @IntDef({LNB_VOLTAGE_NONE, LNB_VOLTAGE_5V, LNB_VOLTAGE_11V, LNB_VOLTAGE_12V, LNB_VOLTAGE_13V,
-            LNB_VOLTAGE_14V, LNB_VOLTAGE_15V, LNB_VOLTAGE_18V, LNB_VOLTAGE_19V})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LnbVoltage {}
-    /** @hide */
-    public static final int LNB_VOLTAGE_NONE = Constants.LnbVoltage.NONE;
-    /** @hide */
-    public static final int LNB_VOLTAGE_5V = Constants.LnbVoltage.VOLTAGE_5V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_11V = Constants.LnbVoltage.VOLTAGE_11V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_12V = Constants.LnbVoltage.VOLTAGE_12V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_13V = Constants.LnbVoltage.VOLTAGE_13V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_14V = Constants.LnbVoltage.VOLTAGE_14V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_15V = Constants.LnbVoltage.VOLTAGE_15V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_18V = Constants.LnbVoltage.VOLTAGE_18V;
-    /** @hide */
-    public static final int LNB_VOLTAGE_19V = Constants.LnbVoltage.VOLTAGE_19V;
-
-    /** @hide */
-    @IntDef({LNB_TONE_NONE, LNB_TONE_CONTINUOUS})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LnbTone {}
-    /** @hide */
-    public static final int LNB_TONE_NONE = Constants.LnbTone.NONE;
-    /** @hide */
-    public static final int LNB_TONE_CONTINUOUS = Constants.LnbTone.CONTINUOUS;
-
-    /** @hide */
-    @IntDef({LNB_POSITION_UNDEFINED, LNB_POSITION_A, LNB_POSITION_B})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LnbPosition {}
-    /** @hide */
-    public static final int LNB_POSITION_UNDEFINED = Constants.LnbPosition.UNDEFINED;
-    /** @hide */
-    public static final int LNB_POSITION_A = Constants.LnbPosition.POSITION_A;
-    /** @hide */
-    public static final int LNB_POSITION_B = Constants.LnbPosition.POSITION_B;
-
-
-    /** @hide */
     @IntDef({RESULT_SUCCESS, RESULT_UNAVAILABLE, RESULT_NOT_INITIALIZED, RESULT_INVALID_STATE,
             RESULT_INVALID_ARGUMENT, RESULT_OUT_OF_MEMORY, RESULT_UNKNOWN_ERROR})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Result {}
-    /** @hide */
+
+    /**
+     * Operation succeeded.
+     * @hide
+     */
     public static final int RESULT_SUCCESS = Constants.Result.SUCCESS;
-    /** @hide */
+    /**
+     * Operation failed because the corresponding resources are not available.
+     * @hide
+     */
     public static final int RESULT_UNAVAILABLE = Constants.Result.UNAVAILABLE;
-    /** @hide */
+    /**
+     * Operation failed because the corresponding resources are not initialized.
+     * @hide
+     */
     public static final int RESULT_NOT_INITIALIZED = Constants.Result.NOT_INITIALIZED;
-    /** @hide */
+    /**
+     * Operation failed because it's not in a valid state.
+     * @hide
+     */
     public static final int RESULT_INVALID_STATE = Constants.Result.INVALID_STATE;
-    /** @hide */
+    /**
+     * Operation failed because there are invalid arguments.
+     * @hide
+     */
     public static final int RESULT_INVALID_ARGUMENT = Constants.Result.INVALID_ARGUMENT;
-    /** @hide */
+    /**
+     * Memory allocation failed.
+     * @hide
+     */
     public static final int RESULT_OUT_OF_MEMORY = Constants.Result.OUT_OF_MEMORY;
-    /** @hide */
+    /**
+     * Operation failed due to unknown errors.
+     * @hide
+     */
     public static final int RESULT_UNKNOWN_ERROR = Constants.Result.UNKNOWN_ERROR;
 
     private TunerConstants() {
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index 16308ce..aec8ce8 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -16,33 +16,153 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
- * Frontend settings for analog.
+ * Frontend settings for analog tuner.
+ *
  * @hide
  */
 public class AnalogFrontendSettings extends FrontendSettings {
-    private int mAnalogType;
-    private int mSifStandard;
+    /** @hide */
+    @IntDef(flag = true, value = {SIGNAL_TYPE_UNDEFINED, SIGNAL_TYPE_PAL, SIGNAL_TYPE_SECAM,
+            SIGNAL_TYPE_NTSC})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SignalType {}
+
+    /**
+     * Undefined analog signal type.
+     */
+    public static final int SIGNAL_TYPE_UNDEFINED = Constants.FrontendAnalogType.UNDEFINED;
+    /**
+     * PAL analog signal type.
+     */
+    public static final int SIGNAL_TYPE_PAL = Constants.FrontendAnalogType.PAL;
+    /**
+     * SECM analog signal type.
+     */
+    public static final int SIGNAL_TYPE_SECAM = Constants.FrontendAnalogType.SECAM;
+    /**
+     * NTSC analog signal type.
+     */
+    public static final int SIGNAL_TYPE_NTSC = Constants.FrontendAnalogType.NTSC;
+
+
+    /** @hide */
+    @IntDef(flag = true, value = {SIF_UNDEFINED, SIF_BG, SIF_BG_A2, SIF_BG_NICAM, SIF_I, SIF_DK,
+            SIF_DK1, SIF_DK2, SIF_DK3, SIF_DK_NICAM, SIF_L, SIF_M, SIF_M_BTSC, SIF_M_A2,
+            SIF_M_EIA_J, SIF_I_NICAM, SIF_L_NICAM, SIF_L_PRIME})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SifStandard {}
+
+    /**
+     * Undefined Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_UNDEFINED = Constants.FrontendAnalogSifStandard.UNDEFINED;
+    /**
+     * BG Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_BG = Constants.FrontendAnalogSifStandard.BG;
+    /**
+     * BG-A2 Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_BG_A2 = Constants.FrontendAnalogSifStandard.BG_A2;
+    /**
+     * BG-NICAM Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_BG_NICAM = Constants.FrontendAnalogSifStandard.BG_NICAM;
+    /**
+     * I Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_I = Constants.FrontendAnalogSifStandard.I;
+    /**
+     * DK Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_DK = Constants.FrontendAnalogSifStandard.DK;
+    /**
+     * DK1 Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_DK1 = Constants.FrontendAnalogSifStandard.DK1;
+    /**
+     * DK2 Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_DK2 = Constants.FrontendAnalogSifStandard.DK2;
+    /**
+     * DK3 Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_DK3 = Constants.FrontendAnalogSifStandard.DK3;
+    /**
+     * DK-NICAM Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_DK_NICAM = Constants.FrontendAnalogSifStandard.DK_NICAM;
+    /**
+     * L Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_L = Constants.FrontendAnalogSifStandard.L;
+    /**
+     * M Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_M = Constants.FrontendAnalogSifStandard.M;
+    /**
+     * M-BTSC Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_M_BTSC = Constants.FrontendAnalogSifStandard.M_BTSC;
+    /**
+     * M-A2 Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_M_A2 = Constants.FrontendAnalogSifStandard.M_A2;
+    /**
+     * M-EIA-J Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_M_EIA_J = Constants.FrontendAnalogSifStandard.M_EIA_J;
+    /**
+     * I-NICAM Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_I_NICAM = Constants.FrontendAnalogSifStandard.I_NICAM;
+    /**
+     * L-NICAM Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_L_NICAM = Constants.FrontendAnalogSifStandard.L_NICAM;
+    /**
+     * L-PRIME Analog Standard Interchange Format (SIF).
+     */
+    public static final int SIF_L_PRIME = Constants.FrontendAnalogSifStandard.L_PRIME;
+
+
+    private final int mAnalogType;
+    private final int mSifStandard;
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ANALOG;
+        return FrontendSettings.TYPE_ANALOG;
     }
 
+
+    /**
+     * Gets analog signal type.
+     */
+    @SignalType
     public int getAnalogType() {
         return mAnalogType;
     }
 
+    /**
+     * Gets Standard Interchange Format (SIF).
+     */
+    @SifStandard
     public int getSifStandard() {
         return mSifStandard;
     }
 
     /**
-     * Creates a new builder object.
+     * Creates a builder for {@link AnalogFrontendSettings}.
      */
+    @NonNull
     public static Builder newBuilder() {
         return new Builder();
     }
@@ -54,7 +174,7 @@
     }
 
     /**
-     * Builder for FrontendAnalogSettings.
+     * Builder for {@link AnalogFrontendSettings}.
      */
     public static class Builder {
         private int mFrequency;
@@ -64,8 +184,9 @@
         private Builder() {}
 
         /**
-         * Sets frequency.
+         * Sets frequency in Hz.
          */
+        @NonNull
         public Builder setFrequency(int frequency) {
             mFrequency = frequency;
             return this;
@@ -74,22 +195,25 @@
         /**
          * Sets analog type.
          */
-        public Builder setAnalogType(int analogType) {
+        @NonNull
+        public Builder setAnalogType(@SignalType int analogType) {
             mAnalogType = analogType;
             return this;
         }
 
         /**
-         * Sets sif standard.
+         * Sets Standard Interchange Format (SIF).
          */
-        public Builder setSifStandard(int sifStandard) {
+        @NonNull
+        public Builder setSifStandard(@SifStandard int sifStandard) {
             mSifStandard = sifStandard;
             return this;
         }
 
         /**
-         * Builds a FrontendAnalogSettings instance.
+         * Builds a {@link AnalogFrontendSettings} object.
          */
+        @NonNull
         public AnalogFrontendSettings build() {
             return new AnalogFrontendSettings(mFrequency, mAnalogType, mSifStandard);
         }
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index bce8a64..5b09e36 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -16,10 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 import java.util.List;
 
 /**
@@ -37,6 +33,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ATSC3;
+        return FrontendSettings.TYPE_ATSC3;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index 14c5cdd..19e18d0 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
@@ -16,9 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for ATSC.
  * @hide
@@ -32,6 +29,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ATSC;
+        return FrontendSettings.TYPE_ATSC;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 07e49ff..60618f6 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -16,9 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for DVBC.
  * @hide
@@ -37,6 +34,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_DVBC;
+        return FrontendSettings.TYPE_DVBC;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 23c0a7b1..586787f 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -16,9 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for DVBS.
  * @hide
@@ -38,6 +35,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_DVBS;
+        return FrontendSettings.TYPE_DVBS;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index eec00f3..6b350a7 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -16,10 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for DVBT.
  * @hide
@@ -45,6 +41,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_DVBT;
+        return FrontendSettings.TYPE_DVBT;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index 5d03570..99e8dd2 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -16,7 +16,7 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.TunerConstants.FrontendType;
+import android.media.tv.tuner.frontend.FrontendSettings.Type;
 
 /**
  * Frontend info.
@@ -54,7 +54,7 @@
         return mId;
     }
     /** Gets frontend type. */
-    @FrontendType
+    @Type
     public int getType() {
         return mType;
     }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
new file mode 100644
index 0000000..210aef4
--- /dev/null
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.frontend;
+
+import android.annotation.IntDef;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Frontend settings for tune and scan operations.
+ *
+ * @hide
+ */
+public abstract class FrontendSettings {
+    /** @hide */
+    @IntDef({TYPE_UNDEFINED, TYPE_ANALOG, TYPE_ATSC, TYPE_ATSC3, TYPE_DVBC, TYPE_DVBS, TYPE_DVBT,
+            TYPE_ISDBS, TYPE_ISDBS3, TYPE_ISDBT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /**
+     * Undefined frontend type.
+     */
+    public static final int TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED;
+    /**
+     * Analog frontend type.
+     */
+    public static final int TYPE_ANALOG = Constants.FrontendType.ANALOG;
+    /**
+     * Advanced Television Systems Committee (ATSC) frontend type.
+     */
+    public static final int TYPE_ATSC = Constants.FrontendType.ATSC;
+    /**
+     * Advanced Television Systems Committee 3.0 (ATSC-3) frontend type.
+     */
+    public static final int TYPE_ATSC3 = Constants.FrontendType.ATSC3;
+    /**
+     * Digital Video Broadcasting-Cable (DVB-C) frontend type.
+     */
+    public static final int TYPE_DVBC = Constants.FrontendType.DVBC;
+    /**
+     * Digital Video Broadcasting-Satellite (DVB-S) frontend type.
+     */
+    public static final int TYPE_DVBS = Constants.FrontendType.DVBS;
+    /**
+     * Digital Video Broadcasting-Terrestrial (DVB-T) frontend type.
+     */
+    public static final int TYPE_DVBT = Constants.FrontendType.DVBT;
+    /**
+     * Integrated Services Digital Broadcasting-Satellite (ISDB-S) frontend type.
+     */
+    public static final int TYPE_ISDBS = Constants.FrontendType.ISDBS;
+    /**
+     * Integrated Services Digital Broadcasting-Satellite 3 (ISDB-S3) frontend type.
+     */
+    public static final int TYPE_ISDBS3 = Constants.FrontendType.ISDBS3;
+    /**
+     * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T) frontend type.
+     */
+    public static final int TYPE_ISDBT = Constants.FrontendType.ISDBT;
+
+    private final int mFrequency;
+
+    /** @hide */
+    public FrontendSettings(int frequency) {
+        mFrequency = frequency;
+    }
+
+    /**
+     * Returns the frontend type.
+     */
+    @Type
+    public abstract int getType();
+
+    /**
+     * Gets the frequency.
+     *
+     * @return the frequency in Hz.
+     */
+    public int getFrequency() {
+        return mFrequency;
+    }
+
+}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 89ec536..fb5d62a 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -16,13 +16,13 @@
 
 package android.media.tv.tuner.frontend;
 
+import android.media.tv.tuner.Lnb;
 import android.media.tv.tuner.TunerConstants;
 import android.media.tv.tuner.TunerConstants.FrontendDvbcSpectralInversion;
 import android.media.tv.tuner.TunerConstants.FrontendDvbtHierarchy;
 import android.media.tv.tuner.TunerConstants.FrontendInnerFec;
 import android.media.tv.tuner.TunerConstants.FrontendModulation;
 import android.media.tv.tuner.TunerConstants.FrontendStatusType;
-import android.media.tv.tuner.TunerConstants.LnbVoltage;
 
 /**
  * Frontend status
@@ -128,7 +128,7 @@
         return (int) mValue;
     }
     /** Power Voltage Type for LNB. */
-    @LnbVoltage
+    @Lnb.Voltage
     public int getLnbVoltage() {
         if (mType != TunerConstants.FRONTEND_STATUS_TYPE_LNB_VOLTAGE) {
             throw new IllegalStateException();
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index 736d0b1..45932a7 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -16,9 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for ISDBS-3.
  * @hide
@@ -37,6 +34,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ISDBS3;
+        return FrontendSettings.TYPE_ISDBS3;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index 7fd5da7..e726a9a 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -16,9 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for ISDBS.
  * @hide
@@ -37,6 +34,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ISDBS;
+        return FrontendSettings.TYPE_ISDBS;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index 3f83267..f2b7d24 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
@@ -16,10 +16,6 @@
 
 package android.media.tv.tuner.frontend;
 
-
-import android.media.tv.tuner.FrontendSettings;
-import android.media.tv.tuner.TunerConstants;
-
 /**
  * Frontend settings for ISDBT.
  * @hide
@@ -37,6 +33,6 @@
 
     @Override
     public int getType() {
-        return TunerConstants.FRONTEND_TYPE_ISDBT;
+        return FrontendSettings.TYPE_ISDBT;
     }
 }
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index 24ea3cf..6554267 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -16,11 +16,8 @@
 
 package android.telephony;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
-import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -30,16 +27,22 @@
 
 /**
  * Manages MMS operations such as sending multimedia messages.
+ * Get this object by calling the static method {@link #getInstance()}.
+ * @hide
  */
-public final class MmsManager {
+public class MmsManager {
     private static final String TAG = "MmsManager";
-    private final Context mContext;
+
+    /** Singleton object constructed during class initialization. */
+    private static final MmsManager sInstance = new MmsManager();
 
     /**
-     * @hide
+     * Get the MmsManager singleton instance.
+     *
+     * @return the {@link MmsManager} singleton instance.
      */
-    public MmsManager(@NonNull Context context) {
-        mContext = context;
+    public static MmsManager getInstance() {
+        return sInstance;
     }
 
     /**
@@ -53,9 +56,8 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message
      *                   is successfully sent, or failed
      */
-    public void sendMultimediaMessage(int subId, @NonNull Uri contentUri,
-            @Nullable String locationUrl, @Nullable Bundle configOverrides,
-            @Nullable PendingIntent sentIntent) {
+    public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl,
+            Bundle configOverrides, PendingIntent sentIntent) {
         try {
             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
             if (iMms == null) {
@@ -82,9 +84,8 @@
      *  broadcast when the message is downloaded, or the download is failed
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
      */
-    public void downloadMultimediaMessage(int subId, @NonNull String locationUrl,
-            @NonNull Uri contentUri, @Nullable Bundle configOverrides,
-            @Nullable PendingIntent downloadedIntent) {
+    public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri,
+            Bundle configOverrides, PendingIntent downloadedIntent) {
         try {
             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
             if (iMms == null) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index f7802d2..6ec3854 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -19,14 +19,19 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.util.leak.LeakDetector;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Car specific notification entry manager that does nothing when adding a notification.
  *
@@ -42,8 +47,12 @@
             NotificationGroupManager groupManager,
             NotificationRankingManager rankingManager,
             KeyguardEnvironment keyguardEnvironment,
-            FeatureFlags featureFlags) {
-        super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags);
+            FeatureFlags featureFlags,
+            Lazy<NotificationRowBinder> notificationRowBinderLazy,
+            Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
+            LeakDetector leakDetector) {
+        super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags,
+                notificationRowBinderLazy, notificationRemoteInputManagerLazy, leakDetector);
     }
 
     @Override
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 3c3ebe2..4521f5f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.car;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
 import android.animation.Animator;
@@ -107,6 +106,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -268,7 +268,6 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
             Lazy<NewNotifPipeline> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
@@ -334,6 +333,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            NotificationRowBinderImpl notificationRowBinder,
             DismissCallbackRegistry dismissCallbackRegistry,
             /* Car Settings injected components. */
             CarServiceProvider carServiceProvider,
@@ -355,7 +355,6 @@
                 headsUpManagerPhone,
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
-                allowNotificationLongPress,
                 newNotifPipeline,
                 falsingManager,
                 broadcastDispatcher,
@@ -421,6 +420,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                notificationRowBinder,
                 dismissCallbackRegistry);
         mScrimController = scrimController;
         mLockscreenLockIconController = lockscreenLockIconController;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index a1eccce..e5a091f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.car;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
 import android.content.Context;
@@ -67,6 +66,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -138,7 +138,6 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
             Lazy<NewNotifPipeline> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
@@ -204,6 +203,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            NotificationRowBinderImpl notificationRowBinder,
             DismissCallbackRegistry dismissCallbackRegistry,
             CarServiceProvider carServiceProvider,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
@@ -224,7 +224,6 @@
                 headsUpManagerPhone,
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
-                allowNotificationLongPress,
                 newNotifPipeline,
                 falsingManager,
                 broadcastDispatcher,
@@ -289,6 +288,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                notificationRowBinder,
                 dismissCallbackRegistry,
                 carServiceProvider,
                 powerManagerHelperLazy,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 347d6c2..1c63efc 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -194,6 +194,9 @@
 
     <uses-permission android:name="android.permission.MANAGE_APPOPS" />
 
+    <!-- Permission required for storage tests - FuseDaemonHostTest -->
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
     <!-- Permission needed to test tcp keepalive offload. -->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 97224f1..ccbbb24 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -111,7 +111,10 @@
     }
 
     private final Context mContext;
+    /** Bubbles that are actively in the stack. */
     private final List<Bubble> mBubbles;
+    /** Bubbles that are being loaded but haven't been added to the stack just yet. */
+    private final List<Bubble> mPendingBubbles;
     private Bubble mSelectedBubble;
     private boolean mExpanded;
     private final int mMaxBubbles;
@@ -143,6 +146,7 @@
     public BubbleData(Context context) {
         mContext = context;
         mBubbles = new ArrayList<>();
+        mPendingBubbles = new ArrayList<>();
         mStateChange = new Update(mBubbles);
         mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
     }
@@ -188,7 +192,15 @@
     Bubble getOrCreateBubble(NotificationEntry entry) {
         Bubble bubble = getBubbleWithKey(entry.getKey());
         if (bubble == null) {
+            // Check for it in pending
+            for (int i = 0; i < mPendingBubbles.size(); i++) {
+                Bubble b = mPendingBubbles.get(i);
+                if (b.getKey().equals(entry.getKey())) {
+                    return b;
+                }
+            }
             bubble = new Bubble(entry);
+            mPendingBubbles.add(bubble);
         } else {
             bubble.setEntry(entry);
         }
@@ -204,7 +216,7 @@
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "notificationEntryUpdated: " + bubble);
         }
-
+        mPendingBubbles.remove(bubble); // No longer pending once we're here
         Bubble prevBubble = getBubbleWithKey(bubble.getKey());
         suppressFlyout |= !shouldShowFlyout(bubble.getEntry());
 
@@ -377,6 +389,12 @@
     }
 
     private void doRemove(String key, @DismissReason int reason) {
+        //  If it was pending remove it
+        for (int i = 0; i < mPendingBubbles.size(); i++) {
+            if (mPendingBubbles.get(i).getKey().equals(key)) {
+                mPendingBubbles.remove(mPendingBubbles.get(i));
+            }
+        }
         int indexToRemove = indexForKey(key);
         if (indexToRemove == -1) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 6744d74..20917bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -21,9 +21,12 @@
 import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.classifier.FalsingManagerProxy;
 import com.android.systemui.doze.DozeHost;
+import com.android.systemui.globalactions.GlobalActionsComponent;
+import com.android.systemui.globalactions.GlobalActionsImpl;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.PowerNotificationWarnings;
@@ -99,6 +102,17 @@
     /**
      */
     @Binds
+    public abstract GlobalActions provideGlobalActions(GlobalActionsImpl controllerImpl);
+
+    /**
+     */
+    @Binds
+    public abstract GlobalActions.GlobalActionsManager provideGlobalActionsManager(
+            GlobalActionsComponent controllerImpl);
+
+    /**
+     */
+    @Binds
     public abstract LocationController provideLocationController(
             LocationControllerImpl controllerImpl);
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 26337b1..3aa14a3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -26,17 +26,24 @@
 import android.app.NotificationManager;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.res.Resources;
 import android.hardware.SensorPrivacyManager;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.Vibrator;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -66,6 +73,12 @@
         return context.getSystemService(AccessibilityManager.class);
     }
 
+    @Provides
+    @Singleton
+    static ActivityManager provideActivityManager(Context context) {
+        return context.getSystemService(ActivityManager.class);
+    }
+
     @Singleton
     @Provides
     static AlarmManager provideAlarmManager(Context context) {
@@ -74,10 +87,21 @@
 
     @Provides
     @Singleton
-    static ActivityManager provideActivityManager(Context context) {
-        return context.getSystemService(ActivityManager.class);
+    static AudioManager provideAudioManager(Context context) {
+        return context.getSystemService(AudioManager.class);
     }
 
+    @Provides
+    @Singleton
+    static ConnectivityManager provideConnectivityManagager(Context context) {
+        return context.getSystemService(ConnectivityManager.class);
+    }
+
+    @Provides
+    @Singleton
+    static ContentResolver provideContentResolver(Context context) {
+        return context.getContentResolver();
+    }
 
     @Provides
     @DisplayId
@@ -185,6 +209,31 @@
 
     @Provides
     @Singleton
+    static TelecomManager provideTelecomManager(Context context) {
+        return context.getSystemService(TelecomManager.class);
+    }
+
+    @Provides
+    @Singleton
+    static TelephonyManager provideTelephonyManager(Context context) {
+        return context.getSystemService(TelephonyManager.class);
+    }
+
+    @Provides
+    @Singleton
+    static TrustManager provideTrustManager(Context context) {
+        return context.getSystemService(TrustManager.class);
+    }
+
+    @Provides
+    @Singleton
+    @Nullable
+    static Vibrator provideVibrator(Context context) {
+        return context.getSystemService(Vibrator.class);
+    }
+
+    @Provides
+    @Singleton
     static UserManager provideUserManager(Context context) {
         return context.getSystemService(UserManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 58ddda9..b195238 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -31,6 +31,8 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -82,6 +84,11 @@
                 keyguardUpdateMonitor, dumpController);
     }
 
+    /** */
+    @Binds
+    public abstract NotificationRowBinder bindNotificationRowBinder(
+            NotificationRowBinderImpl notificationRowBinder);
+
     @Singleton
     @Provides
     static SysUiState provideSysUiState() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index 19b6f82..e949007a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -19,7 +19,6 @@
 import android.os.ServiceManager;
 
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
@@ -29,6 +28,7 @@
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 import javax.inject.Singleton;
 
 /**
@@ -38,23 +38,29 @@
 public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
 
     private final CommandQueue mCommandQueue;
+    private final ExtensionController mExtensionController;
+    private final Provider<GlobalActions> mGlobalActionsProvider;
     private GlobalActions mPlugin;
     private Extension<GlobalActions> mExtension;
     private IStatusBarService mBarService;
 
     @Inject
-    public GlobalActionsComponent(Context context, CommandQueue commandQueue) {
+    public GlobalActionsComponent(Context context, CommandQueue commandQueue,
+            ExtensionController extensionController,
+            Provider<GlobalActions> globalActionsProvider) {
         super(context);
         mCommandQueue = commandQueue;
+        mExtensionController = extensionController;
+        mGlobalActionsProvider = globalActionsProvider;
     }
 
     @Override
     public void start() {
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
+        mExtension = mExtensionController.newExtension(GlobalActions.class)
                 .withPlugin(GlobalActions.class)
-                .withDefault(() -> new GlobalActionsImpl(mContext, mCommandQueue))
+                .withDefault(mGlobalActionsProvider::get)
                 .withCallback(this::onExtensionCallback)
                 .build();
         mPlugin = mExtension.get();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 3ccad64..fc19fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -21,8 +21,10 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Dialog;
+import android.app.IActivityManager;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -30,11 +32,13 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
@@ -44,13 +48,11 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
-import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.sysprop.TelephonyProperties;
 import android.telecom.TelecomManager;
@@ -92,6 +94,7 @@
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
@@ -106,6 +109,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * Helper to show the global actions dialog.  Each item is an {@link Action} that
  * may show depending on whether the keyguard is showing, and whether the device
@@ -146,6 +151,13 @@
     private final LockPatternUtils mLockPatternUtils;
     private final KeyguardManager mKeyguardManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final ContentResolver mContentResolver;
+    private final Resources mResources;
+    private final UserManager mUserManager;
+    private final TrustManager mTrustManager;
+    private final IActivityManager mIActivityManager;
+    private final TelecomManager mTelecomManager;
+    private final MetricsLogger mMetricsLogger;
 
     private ArrayList<Action> mItems;
     private ActionsDialog mDialog;
@@ -161,8 +173,6 @@
     private boolean mIsWaitingForEcmExit = false;
     private boolean mHasTelephony;
     private boolean mHasVibrator;
-    private boolean mHasLogoutButton;
-    private boolean mHasLockdownButton;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
     private final ScreenshotHelper mScreenshotHelper;
@@ -173,17 +183,32 @@
     /**
      * @param context everything needs a context :(
      */
-    public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs) {
+    @Inject
+    public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs,
+            AudioManager audioManager, IDreamManager iDreamManager,
+            DevicePolicyManager devicePolicyManager, LockPatternUtils lockPatternUtils,
+            KeyguardManager keyguardManager, BroadcastDispatcher broadcastDispatcher,
+            ConnectivityManager connectivityManager, TelephonyManager telephonyManager,
+            ContentResolver contentResolver, @Nullable Vibrator vibrator, @Main Resources resources,
+            ConfigurationController configurationController, ActivityStarter activityStarter,
+            KeyguardStateController keyguardStateController, UserManager userManager,
+            TrustManager trustManager, IActivityManager iActivityManager,
+            TelecomManager telecomManager, MetricsLogger metricsLogger) {
         mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
         mWindowManagerFuncs = windowManagerFuncs;
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.getService(DreamService.DREAM_SERVICE));
-        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        mLockPatternUtils = new LockPatternUtils(mContext);
-        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
+        mAudioManager = audioManager;
+        mDreamManager = iDreamManager;
+        mDevicePolicyManager = devicePolicyManager;
+        mLockPatternUtils = lockPatternUtils;
+        mKeyguardManager = keyguardManager;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mContentResolver = contentResolver;
+        mResources = resources;
+        mUserManager = userManager;
+        mTrustManager = trustManager;
+        mIActivityManager = iActivityManager;
+        mTelecomManager = telecomManager;
+        mMetricsLogger = metricsLogger;
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -192,32 +217,25 @@
         filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
 
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        mHasTelephony = connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
 
         // get notified of phone state changes
-        TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-        mContext.getContentResolver().registerContentObserver(
+        contentResolver.registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                 mAirplaneModeObserver);
-        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = vibrator != null && vibrator.hasVibrator();
 
-        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
+        mShowSilentToggle = SHOW_SILENT_TOGGLE && !resources.getBoolean(
                 R.bool.config_useFixedVolume);
 
         mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
         mScreenshotHelper = new ScreenshotHelper(context);
         mScreenRecordHelper = new ScreenRecordHelper(context);
 
-        Dependency.get(ConfigurationController.class).addCallback(this);
+        configurationController.addCallback(this);
 
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-        KeyguardStateController keyguardStateController =
-                Dependency.get(KeyguardStateController.class);
+        mActivityStarter = activityStarter;
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onUnlockedChanged() {
@@ -343,12 +361,9 @@
         onAirplaneModeChanged();
 
         mItems = new ArrayList<Action>();
-        String[] defaultActions = mContext.getResources().getStringArray(
-                R.array.config_globalActionsList);
+        String[] defaultActions = mResources.getStringArray(R.array.config_globalActionsList);
 
         ArraySet<String> addedKeys = new ArraySet<String>();
-        mHasLogoutButton = false;
-        mHasLockdownButton = false;
         for (int i = 0; i < defaultActions.length; i++) {
             String actionKey = defaultActions[i];
             if (addedKeys.contains(actionKey)) {
@@ -360,7 +375,7 @@
             } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
                 mItems.add(mAirplaneModeOn);
             } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
-                if (Settings.Global.getInt(mContext.getContentResolver(),
+                if (Settings.Global.getInt(mContentResolver,
                         Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
                     mItems.add(new BugReportAction());
                 }
@@ -375,11 +390,10 @@
             } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
                 mItems.add(getSettingsAction());
             } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
-                if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                if (Settings.Secure.getIntForUser(mContentResolver,
                             Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0
                         && shouldDisplayLockdown()) {
                     mItems.add(getLockdownAction());
-                    mHasLockdownButton = true;
                 }
             } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
                 mItems.add(getVoiceAssistAction());
@@ -393,7 +407,6 @@
                 if (mDevicePolicyManager.isLogoutEnabled()
                         && getCurrentUser().id != UserHandle.USER_SYSTEM) {
                     mItems.add(new LogoutAction());
-                    mHasLogoutButton = true;
                 }
             } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
                 if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
@@ -474,8 +487,7 @@
 
         @Override
         public boolean onLongPress() {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+            if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                 mWindowManagerFuncs.reboot(true);
                 return true;
             }
@@ -560,9 +572,8 @@
 
         @Override
         public void onPress() {
-            MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU);
-            Intent intent = mContext.getSystemService(TelecomManager.class)
-                    .createLaunchEmergencyDialerIntent(null /* number */);
+            mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU);
+            Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(null /* number */);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -579,8 +590,7 @@
 
         @Override
         public boolean onLongPress() {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+            if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                 mWindowManagerFuncs.reboot(true);
                 return true;
             }
@@ -618,8 +628,7 @@
                 @Override
                 public void run() {
                     mScreenshotHelper.takeScreenshot(1, true, true, mHandler, null);
-                    MetricsLogger.action(mContext,
-                            MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
+                    mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU);
                 }
             }, 500);
         }
@@ -666,11 +675,11 @@
                 public void run() {
                     try {
                         // Take an "interactive" bugreport.
-                        MetricsLogger.action(mContext,
+                        mMetricsLogger.action(
                                 MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
-                        if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+                        if (!mIActivityManager.launchBugReportHandlerApp()) {
                             Log.w(TAG, "Bugreport handler could not be launched");
-                            ActivityManager.getService().requestInteractiveBugReport();
+                            mIActivityManager.requestInteractiveBugReport();
                         }
                     } catch (RemoteException e) {
                     }
@@ -687,8 +696,8 @@
             }
             try {
                 // Take a "full" bugreport.
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
-                ActivityManager.getService().requestFullBugReport();
+                mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
+                mIActivityManager.requestFullBugReport();
             } catch (RemoteException e) {
             }
             return false;
@@ -726,8 +735,8 @@
             mHandler.postDelayed(() -> {
                 try {
                     int currentUserId = getCurrentUser().id;
-                    ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
-                    ActivityManager.getService().stopUser(currentUserId, true /*force*/, null);
+                    mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
+                    mIActivityManager.stopUser(currentUserId, true /*force*/, null);
                 } catch (RemoteException re) {
                     Log.e(TAG, "Couldn't logout user " + re);
                 }
@@ -834,20 +843,18 @@
     }
 
     private void lockProfiles() {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        final TrustManager tm = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
         final int currentUserId = getCurrentUser().id;
-        final int[] profileIds = um.getEnabledProfileIds(currentUserId);
+        final int[] profileIds = mUserManager.getEnabledProfileIds(currentUserId);
         for (final int id : profileIds) {
             if (id != currentUserId) {
-                tm.setDeviceLockedForUser(id, true);
+                mTrustManager.setDeviceLockedForUser(id, true);
             }
         }
     }
 
     private UserInfo getCurrentUser() {
         try {
-            return ActivityManager.getService().getCurrentUser();
+            return mIActivityManager.getCurrentUser();
         } catch (RemoteException re) {
             return null;
         }
@@ -859,9 +866,8 @@
     }
 
     private void addUsersToMenu(ArrayList<Action> items) {
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.isUserSwitcherEnabled()) {
-            List<UserInfo> users = um.getUsers();
+        if (mUserManager.isUserSwitcherEnabled()) {
+            List<UserInfo> users = mUserManager.getUsers();
             UserInfo currentUser = getCurrentUser();
             for (final UserInfo user : users) {
                 if (user.supportsSwitchToByUser()) {
@@ -875,7 +881,7 @@
                                     + (isCurrentUser ? " \u2714" : "")) {
                         public void onPress() {
                             try {
-                                ActivityManager.getService().switchUser(user.id);
+                                mIActivityManager.switchUser(user.id);
                             } catch (RemoteException re) {
                                 Log.e(TAG, "Couldn't switch user " + re);
                             }
@@ -932,7 +938,7 @@
 
     /** {@inheritDoc} */
     public void onShow(DialogInterface dialog) {
-        MetricsLogger.visible(mContext, MetricsEvent.POWER_MENU);
+        mMetricsLogger.visible(MetricsEvent.POWER_MENU);
     }
 
     /**
@@ -1492,7 +1498,7 @@
         if (mHasTelephony) return;
 
         boolean airplaneModeOn = Settings.Global.getInt(
-                mContext.getContentResolver(),
+                mContentResolver,
                 Settings.Global.AIRPLANE_MODE_ON,
                 0) == 1;
         mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
@@ -1504,7 +1510,7 @@
      */
     private void changeAirplaneModeSystemSetting(boolean on) {
         Settings.Global.putInt(
-                mContext.getContentResolver(),
+                mContentResolver,
                 Settings.Global.AIRPLANE_MODE_ON,
                 on ? 1 : 0);
         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index d385123..c911bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -45,24 +45,32 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import javax.inject.Inject;
+
+import dagger.Lazy;
+
 public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
         PluginListener<GlobalActionsPanelPlugin> {
 
     private static final float SHUTDOWN_SCRIM_ALPHA = 0.95f;
 
     private final Context mContext;
+    private final Lazy<GlobalActionsDialog> mGlobalActionsDialogLazy;
     private final KeyguardStateController mKeyguardStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
     private GlobalActionsPanelPlugin mPlugin;
     private final CommandQueue mCommandQueue;
-    private GlobalActionsDialog mGlobalActions;
+    private GlobalActionsDialog mGlobalActionsDialog;
     private boolean mDisabled;
     private final PluginManager mPluginManager;
     private final String mPluginPackageName;
 
-    public GlobalActionsImpl(Context context, CommandQueue commandQueue) {
+    @Inject
+    public GlobalActionsImpl(Context context, CommandQueue commandQueue,
+            Lazy<GlobalActionsDialog> globalActionsDialogLazy) {
         mContext = context;
+        mGlobalActionsDialogLazy = globalActionsDialogLazy;
         mKeyguardStateController = Dependency.get(KeyguardStateController.class);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
         mPluginManager = Dependency.get(PluginManager.class);
@@ -83,19 +91,17 @@
         mCommandQueue.removeCallback(this);
         mPluginManager.removePluginListener(this);
         if (mPlugin != null) mPlugin.onDestroy();
-        if (mGlobalActions != null) {
-            mGlobalActions.destroy();
-            mGlobalActions = null;
+        if (mGlobalActionsDialog != null) {
+            mGlobalActionsDialog.destroy();
+            mGlobalActionsDialog = null;
         }
     }
 
     @Override
     public void showGlobalActions(GlobalActionsManager manager) {
         if (mDisabled) return;
-        if (mGlobalActions == null) {
-            mGlobalActions = new GlobalActionsDialog(mContext, manager);
-        }
-        mGlobalActions.showDialog(mKeyguardStateController.isShowing(),
+        mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
+        mGlobalActionsDialog.showDialog(mKeyguardStateController.isShowing(),
                 mDeviceProvisionedController.isDeviceProvisioned(),
                 mPlugin != null ? mPlugin : mPanelExtension.get());
         Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
@@ -189,8 +195,8 @@
         final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
         if (displayId != mContext.getDisplayId() || disabled == mDisabled) return;
         mDisabled = disabled;
-        if (disabled && mGlobalActions != null) {
-            mGlobalActions.dismissDialog();
+        if (disabled && mGlobalActionsDialog != null) {
+            mGlobalActionsDialog.dismissDialog();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index dc84b57..9c626f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -307,6 +307,7 @@
             case Icon.TYPE_RESOURCE:
                 return a.getResPackage().equals(b.getResPackage()) && a.getResId() == b.getResId();
             case Icon.TYPE_URI:
+            case Icon.TYPE_URI_ADAPTIVE_BITMAP:
                 return a.getUriString().equals(b.getUriString());
             default:
                 return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index a2578ab..36dcaac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -32,7 +32,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
@@ -68,6 +67,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * NotificationEntryManager is responsible for the adding, removing, and updating of
  * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
@@ -126,8 +127,9 @@
             new ArrayMap<>();
 
     // Lazily retrieved dependencies
-    private NotificationRemoteInputManager mRemoteInputManager;
-    private NotificationRowBinder mNotificationRowBinder;
+    private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy;
+    private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy;
+    private final LeakDetector mLeakDetector;
 
     private final KeyguardEnvironment mKeyguardEnvironment;
     private final NotificationGroupManager mGroupManager;
@@ -173,12 +175,18 @@
             NotificationGroupManager groupManager,
             NotificationRankingManager rankingManager,
             KeyguardEnvironment keyguardEnvironment,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            Lazy<NotificationRowBinder> notificationRowBinderLazy,
+            Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
+            LeakDetector leakDetector) {
         mNotifLog = notifLog;
         mGroupManager = groupManager;
         mRankingManager = rankingManager;
         mKeyguardEnvironment = keyguardEnvironment;
         mFeatureFlags = featureFlags;
+        mNotificationRowBinderLazy = notificationRowBinderLazy;
+        mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
+        mLeakDetector = leakDetector;
     }
 
     /** Once called, the NEM will start processing notification events from system server. */
@@ -204,20 +212,6 @@
         mRemoveInterceptor = interceptor;
     }
 
-    /**
-     * Our dependencies can have cyclic references, so some need to be lazy
-     */
-    private NotificationRemoteInputManager getRemoteInputManager() {
-        if (mRemoteInputManager == null) {
-            mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
-        }
-        return mRemoteInputManager;
-    }
-
-    public void setRowBinder(NotificationRowBinder notificationRowBinder) {
-        mNotificationRowBinder = notificationRowBinder;
-    }
-
     public void setUpWithPresenter(NotificationPresenter presenter,
             NotificationListContainer listContainer,
             HeadsUpManager headsUpManager) {
@@ -468,7 +462,7 @@
                 handleGroupSummaryRemoved(key);
                 removeVisibleNotification(key);
                 updateNotifications("removeNotificationInternal");
-                Dependency.get(LeakDetector.class).trackGarbage(entry);
+                mLeakDetector.trackGarbage(entry);
                 removedByUser |= entryDismissed;
 
                 mNotifLog.log(NotifEvent.NOTIF_REMOVED, entry.getSbn(),
@@ -507,8 +501,8 @@
                 boolean isForeground = (entry.getSbn().getNotification().flags
                         & Notification.FLAG_FOREGROUND_SERVICE) != 0;
                 boolean keepForReply =
-                        getRemoteInputManager().shouldKeepForRemoteInputHistory(childEntry)
-                        || getRemoteInputManager().shouldKeepForSmartReplyHistory(childEntry);
+                        mRemoteInputManagerLazy.get().shouldKeepForRemoteInputHistory(childEntry)
+                        || mRemoteInputManagerLazy.get().shouldKeepForSmartReplyHistory(childEntry);
                 if (isForeground || keepForReply) {
                     // the child is a foreground service notification which we can't remove or it's
                     // a child we're keeping around for reply!
@@ -536,12 +530,13 @@
 
         NotificationEntry entry = new NotificationEntry(notification, ranking);
 
-        Dependency.get(LeakDetector.class).trackInstance(entry);
+        mLeakDetector.trackInstance(entry);
 
         // Construct the expanded view.
         if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
-            requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
-                    REASON_CANCEL));
+            mNotificationRowBinderLazy.get()
+                    .inflateViews(entry, () -> performRemoveNotification(notification,
+                            REASON_CANCEL));
         }
 
         abortExistingInflation(key, "addNotification");
@@ -586,15 +581,16 @@
         }
 
         if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
-            requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
-                    REASON_CANCEL));
+            mNotificationRowBinderLazy.get()
+                    .inflateViews(entry, () -> performRemoveNotification(notification,
+                            REASON_CANCEL));
         }
 
         updateNotifications("updateNotificationInternal");
 
         if (DEBUG) {
             // Is this for you?
-            boolean isForCurrentUser = Dependency.get(KeyguardEnvironment.class)
+            boolean isForCurrentUser = mKeyguardEnvironment
                     .isNotificationForCurrentProfiles(notification);
             Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
         }
@@ -644,11 +640,12 @@
 
         // By comparing the old and new UI adjustments, reinflate the view accordingly.
         for (NotificationEntry entry : entries) {
-            requireBinder().onNotificationRankingUpdated(
-                    entry,
-                    oldImportances.get(entry.getKey()),
-                    oldAdjustments.get(entry.getKey()),
-                    NotificationUiAdjustment.extractFromNotificationEntry(entry));
+            mNotificationRowBinderLazy.get()
+                    .onNotificationRankingUpdated(
+                            entry,
+                            oldImportances.get(entry.getKey()),
+                            oldAdjustments.get(entry.getKey()),
+                            NotificationUiAdjustment.extractFromNotificationEntry(entry));
         }
 
         updateNotifications("updateNotificationRanking");
@@ -728,14 +725,6 @@
         }
     }
 
-    private NotificationRowBinder requireBinder() {
-        if (mNotificationRowBinder == null) {
-            throw new RuntimeException("You must initialize NotificationEntryManager by calling"
-                    + "setRowBinder() before using.");
-        }
-        return mNotificationRowBinder;
-    }
-
     /*
      * -----
      * Annexed from NotificationData below:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 6dc647d..6a2774b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
 
@@ -29,7 +30,6 @@
 import android.view.ViewGroup;
 
 import com.android.internal.util.NotificationMessagingUtil;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -52,27 +52,30 @@
 
 import java.util.Objects;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
 /** Handles inflating and updating views for notifications. */
+@Singleton
 public class NotificationRowBinderImpl implements NotificationRowBinder {
 
     private static final String TAG = "NotificationViewManager";
 
-    private final NotificationGroupManager mGroupManager =
-            Dependency.get(NotificationGroupManager.class);
-    private final NotificationGutsManager mGutsManager =
-            Dependency.get(NotificationGutsManager.class);
-    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
-            Dependency.get(NotificationInterruptionStateProvider.class);
+    private final NotificationGroupManager mGroupManager;
+    private final NotificationGutsManager mGutsManager;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
 
     private final Context mContext;
     private final NotificationMessagingUtil mMessagingUtil;
     private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
             this::logNotificationExpansion;
+    private final NotificationRemoteInputManager mNotificationRemoteInputManager;
+    private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     private final boolean mAllowLongPress;
     private final KeyguardBypassController mKeyguardBypassController;
     private final StatusBarStateController mStatusBarStateController;
 
-    private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
     private HeadsUpManager mHeadsUpManager;
@@ -82,27 +85,31 @@
     private NotificationClicker mNotificationClicker;
     private final NotificationLogger mNotificationLogger;
 
+    @Inject
     public NotificationRowBinderImpl(
             Context context,
-            boolean allowLongPress,
+            NotificationRemoteInputManager notificationRemoteInputManager,
+            NotificationLockscreenUserManager notificationLockscreenUserManager,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
             KeyguardBypassController keyguardBypassController,
             StatusBarStateController statusBarStateController,
+            NotificationGroupManager notificationGroupManager,
+            NotificationGutsManager notificationGutsManager,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationLogger logger) {
         mContext = context;
         mMessagingUtil = new NotificationMessagingUtil(context);
+        mNotificationRemoteInputManager = notificationRemoteInputManager;
+        mNotificationLockscreenUserManager = notificationLockscreenUserManager;
         mAllowLongPress = allowLongPress;
         mKeyguardBypassController = keyguardBypassController;
         mStatusBarStateController = statusBarStateController;
+        mGroupManager = notificationGroupManager;
+        mGutsManager = notificationGutsManager;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mNotificationLogger = logger;
     }
 
-    private NotificationRemoteInputManager getRemoteInputManager() {
-        if (mRemoteInputManager == null) {
-            mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
-        }
-        return mRemoteInputManager;
-    }
-
     /**
      * Sets up late-bound dependencies for this component.
      */
@@ -167,7 +174,7 @@
             row.setLongPressListener(mGutsManager::openGuts);
         }
         mListContainer.bindRow(row);
-        getRemoteInputManager().bindRow(row);
+        mNotificationRemoteInputManager.bindRow(row);
 
         // Get the app name.
         // Note that Notification.Builder#bindHeaderAppName has similar logic
@@ -263,8 +270,7 @@
         if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
             row.setInflationFlags(FLAG_CONTENT_VIEW_HEADS_UP);
         }
-        row.setNeedsRedaction(
-                Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
+        row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry));
         row.inflateViews();
 
         // bind the click event to the content area
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index eeb54ab..2436bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -76,6 +76,7 @@
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println();
         pw.println(TAG + ":");
         for (Coordinator c : mCoordinators) {
             pw.println("\t" + c.getClass());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
index 069c15f..c3e3c53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
@@ -259,7 +259,7 @@
         pw.println("Coalesced notifications:");
         for (EventBatch batch : mBatches.values()) {
             pw.println("   Batch " + batch.mGroupKey + ":");
-            pw.println("       Created" + (now - batch.mCreatedTimestamp) + "ms ago");
+            pw.println("       Created " + (now - batch.mCreatedTimestamp) + "ms ago");
             for (CoalescedEvent event : batch.mMembers) {
                 pw.println("       " + event.getKey());
                 eventCount++;
@@ -299,5 +299,5 @@
         void onNotificationBatchPosted(List<CoalescedEvent> events);
     }
 
-    private static final int GROUP_LINGER_DURATION = 40;
+    private static final int GROUP_LINGER_DURATION = 500;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ccc86b1..189d3b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -29,7 +29,6 @@
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -365,7 +364,6 @@
     private final HeadsUpManagerPhone mHeadsUpManager;
     private final DynamicPrivacyController mDynamicPrivacyController;
     private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
-    private final boolean mAllowNotificationLongPress;
     private final Lazy<NewNotifPipeline> mNewNotifPipeline;
     private final FalsingManager mFalsingManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -388,6 +386,7 @@
     private final KeyguardDismissUtil mKeyguardDismissUtil;
     private final ExtensionController mExtensionController;
     private final UserInfoControllerImpl mUserInfoControllerImpl;
+    private final NotificationRowBinderImpl mNotificationRowBinder;
     private final DismissCallbackRegistry mDismissCallbackRegistry;
 
     // expanded notifications
@@ -626,7 +625,6 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
             Lazy<NewNotifPipeline> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
@@ -693,6 +691,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            NotificationRowBinderImpl notificationRowBinder,
             DismissCallbackRegistry dismissCallbackRegistry) {
         super(context);
         mFeatureFlags = featureFlags;
@@ -707,7 +706,6 @@
         mHeadsUpManager = headsUpManagerPhone;
         mDynamicPrivacyController = dynamicPrivacyController;
         mBypassHeadsUpNotifier = bypassHeadsUpNotifier;
-        mAllowNotificationLongPress = allowNotificationLongPress;
         mNewNotifPipeline = newNotifPipeline;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -772,6 +770,7 @@
         mKeyguardDismissUtil = keyguardDismissUtil;
         mExtensionController = extensionController;
         mUserInfoControllerImpl = userInfoControllerImpl;
+        mNotificationRowBinder = notificationRowBinder;
         mDismissCallbackRegistry = dismissCallbackRegistry;
 
         mBubbleExpandListener =
@@ -1237,19 +1236,11 @@
                 mStatusBarWindowViewController, this, mNotificationPanelViewController,
                 (NotificationListContainer) mStackScroller);
 
-        final NotificationRowBinderImpl rowBinder =
-                new NotificationRowBinderImpl(
-                        mContext,
-                        mAllowNotificationLongPress,
-                        mKeyguardBypassController,
-                        mStatusBarStateController,
-                        mNotificationLogger);
-
         // TODO: inject this.
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
                 mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
-                mNotificationAlertingManager, rowBinder, mKeyguardStateController,
+                mNotificationAlertingManager, mNotificationRowBinder, mKeyguardStateController,
                 mKeyguardIndicationController,
                 this /* statusBar */, mShadeController, mCommandQueue, mInitController);
 
@@ -1273,20 +1264,19 @@
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
 
         if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
-            mEntryManager.setRowBinder(rowBinder);
-            rowBinder.setInflationCallback(mEntryManager);
+            mNotificationRowBinder.setInflationCallback(mEntryManager);
         }
 
         mRemoteInputUriController.attach(mEntryManager);
 
-        rowBinder.setNotificationClicker(new NotificationClicker(
+        mNotificationRowBinder.setNotificationClicker(new NotificationClicker(
                 Optional.of(this), mBubbleController, mNotificationActivityStarter));
 
         mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
         mNotificationListController.bind();
 
         if (mFeatureFlags.isNewNotifPipelineEnabled()) {
-            mNewNotifPipeline.get().initialize(mNotificationListener, rowBinder);
+            mNewNotifPipeline.get().initialize(mNotificationListener, mNotificationRowBinder);
         }
         mEntryManager.attach(mNotificationListener);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 153ca22..be7f0a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
 import android.content.Context;
@@ -66,6 +65,7 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -117,7 +117,6 @@
             HeadsUpManagerPhone headsUpManagerPhone,
             DynamicPrivacyController dynamicPrivacyController,
             BypassHeadsUpNotifier bypassHeadsUpNotifier,
-            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
             Lazy<NewNotifPipeline> newNotifPipeline,
             FalsingManager falsingManager,
             BroadcastDispatcher broadcastDispatcher,
@@ -184,6 +183,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            NotificationRowBinderImpl notificationRowBinder,
             DismissCallbackRegistry dismissCallbackRegistry) {
         return new StatusBar(
                 context,
@@ -199,7 +199,6 @@
                 headsUpManagerPhone,
                 dynamicPrivacyController,
                 bypassHeadsUpNotifier,
-                allowNotificationLongPress,
                 newNotifPipeline,
                 falsingManager,
                 broadcastDispatcher,
@@ -265,6 +264,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                notificationRowBinder,
                 dismissCallbackRegistry);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 6b842d5..5916180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -654,7 +654,7 @@
     }
 
     boolean isDataDisabled() {
-        return !mPhone.isDataCapable();
+        return !mPhone.isDataConnectionEnabled();
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 7cdba86..cc6d607 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -83,17 +83,19 @@
      * Provide a Background-Thread Executor by default.
      */
     @Provides
+    @Singleton
     public static Executor provideExecutor(@Background Looper looper) {
-        return new ExecutorImpl(new Handler(looper));
+        return new ExecutorImpl(looper);
     }
 
     /**
      * Provide a Background-Thread Executor.
      */
     @Provides
+    @Singleton
     @Background
     public static Executor provideBackgroundExecutor(@Background Looper looper) {
-        return new ExecutorImpl(new Handler(looper));
+        return new ExecutorImpl(looper);
     }
 
     /**
@@ -109,26 +111,29 @@
      * Provide a Background-Thread Executor by default.
      */
     @Provides
+    @Singleton
     public static DelayableExecutor provideDelayableExecutor(@Background Looper looper) {
-        return new ExecutorImpl(new Handler(looper));
+        return new ExecutorImpl(looper);
     }
 
     /**
      * Provide a Background-Thread Executor.
      */
     @Provides
+    @Singleton
     @Background
     public static DelayableExecutor provideBackgroundDelayableExecutor(@Background Looper looper) {
-        return new ExecutorImpl(new Handler(looper));
+        return new ExecutorImpl(looper);
     }
 
     /**
      * Provide a Main-Thread Executor.
      */
     @Provides
+    @Singleton
     @Main
     public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
-        return new ExecutorImpl(new Handler(looper));
+        return new ExecutorImpl(looper);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
index 7e77321..2bbf950 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
@@ -17,37 +17,69 @@
 package com.android.systemui.util.concurrency;
 
 import android.os.Handler;
-import android.os.HandlerExecutor;
+import android.os.Looper;
 import android.os.Message;
 
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Implementations of {@link DelayableExecutor} for SystemUI.
  */
-public class ExecutorImpl extends HandlerExecutor implements DelayableExecutor {
+public class ExecutorImpl implements DelayableExecutor {
     private final Handler mHandler;
 
-    public ExecutorImpl(Handler handler) {
-        super(handler);
-        mHandler = handler;
+    ExecutorImpl(Looper looper) {
+        mHandler = new Handler(looper, this::onHandleMessage);
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        if (!mHandler.post(command)) {
+            throw new RejectedExecutionException(mHandler + " is shutting down");
+        }
     }
 
     @Override
     public Runnable executeDelayed(Runnable r, long delay, TimeUnit unit) {
-        Object token = new Object();
-        Message m = mHandler.obtainMessage(0, token);
+        ExecutionToken token = new ExecutionToken(r);
+        Message m = mHandler.obtainMessage(MSG_EXECUTE_RUNNABLE, token);
         mHandler.sendMessageDelayed(m, unit.toMillis(delay));
 
-        return () -> mHandler.removeCallbacksAndMessages(token);
+        return token;
     }
 
     @Override
     public Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit) {
-        Object token = new Object();
-        Message m = mHandler.obtainMessage(0, token);
+        ExecutionToken token = new ExecutionToken(r);
+        Message m = mHandler.obtainMessage(MSG_EXECUTE_RUNNABLE, token);
         mHandler.sendMessageAtTime(m, unit.toMillis(uptimeMillis));
 
-        return () -> mHandler.removeCallbacksAndMessages(token);
+        return token;
     }
+
+    private boolean onHandleMessage(Message msg) {
+        if (msg.what == MSG_EXECUTE_RUNNABLE) {
+            ExecutionToken token = (ExecutionToken) msg.obj;
+            token.runnable.run();
+        } else {
+            throw new IllegalStateException("Unrecognized message: " + msg.what);
+        }
+        return true;
+    }
+
+    private class ExecutionToken implements Runnable {
+        public final Runnable runnable;
+
+        private ExecutionToken(Runnable runnable) {
+            this.runnable = runnable;
+        }
+
+        @Override
+        public void run() {
+            mHandler.removeCallbacksAndMessages(this);
+        }
+    }
+
+    private static final int MSG_EXECUTE_RUNNABLE = 0;
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
index 0c53b03..2ecc8ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
@@ -52,6 +52,7 @@
     @Override
     protected <T> T createDependency(Object key) {
         if (mObjs.containsKey(key)) return (T) mObjs.get(key);
+
         mInstantiatedObjects.add(key);
         return super.createDependency(key);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index cd33cf9..a60fd52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -58,16 +58,13 @@
 import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -81,7 +78,6 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -93,10 +89,10 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.leak.LeakDetector;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -130,22 +126,16 @@
     @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private RankingMap mRankingMap;
     @Mock private RemoteInputController mRemoteInputController;
-
-    // Dependency mocks:
-    @Mock private ForegroundServiceController mForegroundServiceController;
+    @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationGroupManager mGroupManager;
     @Mock private NotificationGutsManager mGutsManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
-    @Mock private NotificationListener mNotificationListener;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock private VisualStabilityManager mVisualStabilityManager;
-    @Mock private MetricsLogger mMetricsLogger;
-    @Mock private SmartReplyController mSmartReplyController;
     @Mock private RowInflaterTask mAsyncInflationTask;
-    @Mock private NotificationRowBinder mMockedRowBinder;
     @Mock private NotifLog mNotifLog;
     @Mock private FeatureFlags mFeatureFlags;
+    @Mock private LeakDetector mLeakDetector;
 
     private int mId;
     private NotificationEntry mEntry;
@@ -192,21 +182,9 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDependency.injectMockDependency(ShadeController.class);
-        mDependency.injectTestDependency(ForegroundServiceController.class,
-                mForegroundServiceController);
-        mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
-                mLockscreenUserManager);
-        mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
-        mDependency.injectTestDependency(NotificationGutsManager.class, mGutsManager);
-        mDependency.injectTestDependency(NotificationRemoteInputManager.class, mRemoteInputManager);
-        mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
-        mDependency.injectTestDependency(DeviceProvisionedController.class,
-                mDeviceProvisionedController);
-        mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
-        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
-        mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
-        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
+        if (!mDependency.hasInstantiatedDependency(SmartReplyController.class)) {
+            mDependency.injectMockDependency(SmartReplyController.class);
+        }
         mDependency.injectMockDependency(NotificationMediaManager.class);
 
         mCountDownLatch = new CountDownLatch(1);
@@ -222,6 +200,17 @@
 
         mEntry.expandedIcon = mock(StatusBarIconView.class);
 
+        NotificationRowBinderImpl notificationRowBinder =
+                new NotificationRowBinderImpl(mContext,
+                        mRemoteInputManager, mLockscreenUserManager,
+                        true, /* allowLongPress */
+                        mock(KeyguardBypassController.class),
+                        mock(StatusBarStateController.class),
+                        mGroupManager,
+                        mGutsManager,
+                        mNotificationInterruptionStateProvider,
+                        mock(NotificationLogger.class));
+
         when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
         when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
         mEntryManager = new TestableNotificationEntryManager(
@@ -237,22 +226,19 @@
                         mock(PeopleNotificationIdentifier.class),
                         mock(HighPriorityProvider.class)),
                 mEnvironment,
-                mFeatureFlags
+                mFeatureFlags,
+                () -> notificationRowBinder,
+                () -> mRemoteInputManager,
+                mLeakDetector
         );
         mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
         mEntryManager.addNotificationEntryListener(mEntryListener);
         mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
 
-        NotificationRowBinderImpl notificationRowBinder =
-                new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
-                        mock(KeyguardBypassController.class),
-                        mock(StatusBarStateController.class),
-                        mock(NotificationLogger.class));
         notificationRowBinder.setUpWithPresenter(
                 mPresenter, mListContainer, mHeadsUpManager, mBindCallback);
         notificationRowBinder.setInflationCallback(mEntryManager);
         notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
-        mEntryManager.setRowBinder(notificationRowBinder);
 
         setUserSentiment(
                 mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
@@ -372,9 +358,6 @@
 
     @Test
     public void testRemoveNotification_whilePending() {
-
-        mEntryManager.setRowBinder(mMockedRowBinder);
-
         mEntryManager.addNotification(mSbn, mRankingMap);
         mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
@@ -447,7 +430,6 @@
     @Test
     public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() {
         // GIVEN an entry manager with a notification
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN a lifetime extender that always tries to extend lifetime
@@ -471,7 +453,6 @@
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
         // GIVEN an entry manager with a notification whose life has been extended
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
         final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender();
         mEntryManager.addNotificationLifetimeExtender(extender);
@@ -490,7 +471,6 @@
     @Test
     public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() {
         // GIVEN an entry manager with a notification whose life has been extended
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
         NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
         when(extender.shouldExtendLifetime(mEntry)).thenReturn(true);
@@ -507,7 +487,6 @@
     @Test
     public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() {
         // GIVEN an entry manager with a notification
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN two lifetime extenders, the first which never extends and the second which
@@ -546,7 +525,6 @@
     @Test
     public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException {
         // GIVEN an entry manager with a notification
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN interceptor that intercepts that entry
@@ -568,7 +546,6 @@
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
         // GIVEN an entry manager with a notification
-        mEntryManager.setRowBinder(mMockedRowBinder);
         mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN interceptor that doesn't intercept
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index 1afee12..bf84f2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -18,12 +18,15 @@
 
 import com.android.systemui.statusbar.FeatureFlags
 import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.NotificationRemoteInputManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder
 import com.android.systemui.statusbar.notification.logging.NotifLog
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.util.leak.LeakDetector
 
 import java.util.concurrent.CountDownLatch
 
@@ -35,8 +38,12 @@
     gm: NotificationGroupManager,
     rm: NotificationRankingManager,
     ke: KeyguardEnvironment,
-    ff: FeatureFlags
-) : NotificationEntryManager(log, gm, rm, ke, ff) {
+    ff: FeatureFlags,
+    rb: dagger.Lazy<NotificationRowBinder>,
+    notificationRemoteInputManagerLazy: dagger.Lazy<NotificationRemoteInputManager>,
+    leakDetector: LeakDetector
+) : NotificationEntryManager(log, gm, rm, ke, ff, rb,
+        notificationRemoteInputManagerLazy, leakDetector) {
 
     public var countDownLatch: CountDownLatch = CountDownLatch(1)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 675b3ef..84c6513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -16,20 +16,17 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
-import android.graphics.drawable.Icon;
 import android.util.ArraySet;
 import android.view.NotificationHeaderView;
 import android.view.View;
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 ea8d4ee..9bd3914 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
@@ -71,6 +71,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
@@ -89,6 +90,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.DeviceConfigProxyFake;
+import com.android.systemui.util.leak.LeakDetector;
 
 import org.junit.After;
 import org.junit.Before;
@@ -170,7 +172,10 @@
                         mock(HighPriorityProvider.class)
                 ),
                 mock(NotificationEntryManager.KeyguardEnvironment.class),
-                mock(FeatureFlags.class));
+                mock(FeatureFlags.class),
+                () -> mock(NotificationRowBinder.class),
+                () -> mRemoteInputManager,
+                mock(LeakDetector.class));
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 7e485f4..560aadb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -120,6 +120,7 @@
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -255,6 +256,7 @@
     @Mock private KeyguardDismissUtil mKeyguardDismissUtil;
     @Mock private ExtensionController mExtensionController;
     @Mock private UserInfoControllerImpl mUserInfoControllerImpl;
+    @Mock private NotificationRowBinderImpl mNotificationRowBinder;
     private ShadeController mShadeController;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
     private InitController mInitController = new InitController();
@@ -344,7 +346,6 @@
                 mHeadsUpManager,
                 mDynamicPrivacyController,
                 mBypassHeadsUpNotifier,
-                true,
                 () -> mNewNotifPipeline,
                 new FalsingManagerFake(),
                 mBroadcastDispatcher,
@@ -413,6 +414,7 @@
                 mKeyguardDismissUtil,
                 mExtensionController,
                 mUserInfoControllerImpl,
+                mNotificationRowBinder,
                 mDismissCallbackRegistry);
 
         when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index c4caeb3..9cb06a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -180,7 +180,7 @@
     protected void setupNetworkController() {
         // For now just pretend to be the data sim, so we can test that too.
         mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-        when(mMockTm.isDataCapable()).thenReturn(true);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(true);
         setDefaultSubId(mSubId);
         setSubscriptions(mSubId);
         mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 95b055c..5a5ef8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -121,7 +121,7 @@
     @Test
     public void testNoInternetIcon_withDefaultSub() {
         setupNetworkController();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -135,7 +135,7 @@
     @Test
     public void testDataDisabledIcon_withDefaultSub() {
         setupNetworkController();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -149,7 +149,7 @@
     @Test
     public void testNonDefaultSIM_showsFullSignal_connected() {
         setupNetworkController();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         setupDefaultSignal();
         setDefaultSubId(mSubId + 1);
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
@@ -164,7 +164,7 @@
     @Test
     public void testNonDefaultSIM_showsFullSignal_disconnected() {
         setupNetworkController();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         setupDefaultSignal();
         setDefaultSubId(mSubId + 1);
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
@@ -429,7 +429,7 @@
     @Test
     public void testDataDisabledIcon_UserNotSetup() {
         setupNetworkController();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
         setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -444,7 +444,7 @@
     @Test
     public void testAlwaysShowDataRatIcon() {
         setupDefaultSignal();
-        when(mMockTm.isDataCapable()).thenReturn(false);
+        when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
         updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
                 TelephonyManager.NETWORK_TYPE_GSM);
 
diff --git a/packages/services/PacProcessor/jni/Android.bp b/packages/services/PacProcessor/jni/Android.bp
index 2a94237..61f8143 100644
--- a/packages/services/PacProcessor/jni/Android.bp
+++ b/packages/services/PacProcessor/jni/Android.bp
@@ -37,4 +37,10 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 312dd46..76572d3 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -811,6 +811,12 @@
     public abstract boolean isApexPackage(String packageName);
 
     /**
+     * Returns list of {@code packageName} of apks inside the given apex.
+     * @param apexPackageName Package name of the apk container of apex
+     */
+    public abstract List<String> getApksInApex(String apexPackageName);
+
+    /**
      * Uninstalls given {@code packageName}.
      *
      * @param packageName apex package to uninstall.
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 32128d5..dc393d1 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -69,7 +69,6 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.stats.location.LocationStatsEnums;
@@ -84,7 +83,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -105,6 +103,7 @@
 import com.android.server.location.MockProvider;
 import com.android.server.location.MockableLocationProvider;
 import com.android.server.location.PassiveProvider;
+import com.android.server.location.UserInfoStore;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
@@ -194,6 +193,7 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final Handler mHandler;
+    private final UserInfoStore mUserInfoStore;
     private final LocationSettingsStore mSettingsStore;
     private final LocationUsageLogger mLocationUsageLogger;
 
@@ -203,7 +203,6 @@
     private PackageManager mPackageManager;
     private PowerManager mPowerManager;
     private ActivityManager mActivityManager;
-    private UserManager mUserManager;
 
     private GeofenceManager mGeofenceManager;
     private LocationFudger mLocationFudger;
@@ -237,10 +236,6 @@
     private final HashMap<String, Location> mLastLocationCoarseInterval =
             new HashMap<>();
 
-    // current active user on the device
-    private int mCurrentUserId;
-    private int[] mCurrentUserProfiles;
-
     @GuardedBy("mLock")
     @PowerManager.LocationPowerSaveMode
     private int mBatterySaverMode;
@@ -248,12 +243,10 @@
     private LocationManagerService(Context context) {
         mContext = context;
         mHandler = FgThread.getHandler();
+        mUserInfoStore = new UserInfoStore(mContext);
         mSettingsStore = new LocationSettingsStore(mContext, mHandler);
         mLocationUsageLogger = new LocationUsageLogger();
 
-        mCurrentUserId = UserHandle.USER_NULL;
-        mCurrentUserProfiles = new int[]{UserHandle.USER_NULL};
-
         // set up passive provider -  we do this early because it has no dependencies on system
         // services or external code that isn't ready yet, and because this allows the variable to
         // be final. other more complex providers are initialized later, when system services are
@@ -277,6 +270,7 @@
     }
 
     private void onSystemReady() {
+        mUserInfoStore.onSystemReady();
         mSettingsStore.onSystemReady();
 
         synchronized (mLock) {
@@ -284,7 +278,6 @@
             mAppOps = mContext.getSystemService(AppOpsManager.class);
             mPowerManager = mContext.getSystemService(PowerManager.class);
             mActivityManager = mContext.getSystemService(ActivityManager.class);
-            mUserManager = mContext.getSystemService(UserManager.class);
 
             mLocationFudger = new LocationFudger(mContext, mHandler);
             mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
@@ -372,10 +365,13 @@
                 }
             }.register(mContext, mHandler.getLooper(), true);
 
+            mUserInfoStore.addListener((oldUserId, newUserId) -> {
+                synchronized (mLock) {
+                    onUserChangedLocked(oldUserId, newUserId);
+                }
+            });
+
             IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
 
@@ -388,14 +384,6 @@
                     }
                     synchronized (mLock) {
                         switch (action) {
-                            case Intent.ACTION_USER_SWITCHED:
-                                onUserChangedLocked(
-                                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                                break;
-                            case Intent.ACTION_MANAGED_PROFILE_ADDED:
-                            case Intent.ACTION_MANAGED_PROFILE_REMOVED:
-                                onUserProfilesChangedLocked();
-                                break;
                             case Intent.ACTION_SCREEN_ON:
                             case Intent.ACTION_SCREEN_OFF:
                                 onScreenStateChangedLocked();
@@ -405,11 +393,10 @@
                 }
             }, UserHandle.ALL, intentFilter, null, mHandler);
 
-            // switching the user from null to system here performs the bulk of the initialization
+            // switching the user from null to current here performs the bulk of the initialization
             // work. the user being changed will cause a reload of all user specific settings, which
             // causes initialization, and propagates changes until a steady state is reached
-            mCurrentUserId = UserHandle.USER_NULL;
-            onUserChangedLocked(ActivityManager.getCurrentUser());
+            onUserChangedLocked(UserHandle.USER_NULL, mUserInfoStore.getCurrentUserId());
         }
     }
 
@@ -551,16 +538,6 @@
     }
 
     @GuardedBy("mLock")
-    private void onUserProfilesChangedLocked() {
-        mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
-    }
-
-    @GuardedBy("mLock")
-    private boolean isCurrentProfileLocked(int userId) {
-        return ArrayUtils.contains(mCurrentUserProfiles, userId);
-    }
-
-    @GuardedBy("mLock")
     private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
         PackageManager pm = mContext.getPackageManager();
         String systemPackageName = mContext.getPackageName();
@@ -568,7 +545,7 @@
 
         List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
                 new Intent(FUSED_LOCATION_SERVICE_ACTION),
-                PackageManager.GET_META_DATA, mCurrentUserId);
+                PackageManager.GET_META_DATA, mUserInfoStore.getCurrentUserId());
         for (ResolveInfo rInfo : rInfos) {
             String packageName = rInfo.serviceInfo.packageName;
 
@@ -752,27 +729,18 @@
     }
 
     @GuardedBy("mLock")
-    private void onUserChangedLocked(int userId) {
-        if (mCurrentUserId == userId) {
-            return;
-        }
-
+    private void onUserChangedLocked(int oldUserId, int newUserId) {
         if (D) {
-            Log.d(TAG, "foreground user is changing to " + userId);
+            Log.d(TAG, "foreground user is changing to " + newUserId);
         }
 
-        int oldUserId = mCurrentUserId;
-        mCurrentUserId = userId;
-        onUserProfilesChangedLocked();
-
-        // let providers know the current user has changed
         for (LocationProviderManager manager : mProviderManagers) {
             // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
             mSettingsStore.setLocationProviderAllowed(manager.getName(),
-                    manager.isUseable(mCurrentUserId), mCurrentUserId);
+                    manager.isUseable(newUserId), newUserId);
 
             manager.onUseableChangedLocked(oldUserId);
-            manager.onUseableChangedLocked(mCurrentUserId);
+            manager.onUseableChangedLocked(newUserId);
         }
     }
 
@@ -786,8 +754,12 @@
         // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
         protected final MockableLocationProvider mProvider;
 
+        // useable state for parent user ids, no entry implies false. location state is only kept
+        // for parent user ids, the location state for a profile user id is assumed to be the same
+        // as for the parent. if querying this structure, ensure that the user id being used is a
+        // parent id or the results may be incorrect.
         @GuardedBy("mLock")
-        private final SparseArray<Boolean> mUseable;  // combined state for each user id
+        private final SparseArray<Boolean> mUseable;
 
         private LocationProviderManager(String name) {
             mName = name;
@@ -795,6 +767,9 @@
 
             // initialize last since this lets our reference escape
             mProvider = new MockableLocationProvider(mContext, mLock, this);
+
+            // we can assume all users start with unuseable location state since the initial state
+            // of all providers is disabled. no need to initialize mUseable further.
         }
 
         public String getName() {
@@ -868,29 +843,6 @@
             mProvider.sendExtraCommand(uid, pid, command, extras);
         }
 
-        public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
-            synchronized (mLock) {
-                pw.print(mName + " provider");
-                if (mProvider.isMock()) {
-                    pw.print(" [mock]");
-                }
-                pw.println(":");
-
-                pw.increaseIndent();
-
-                pw.println("useable=" + isUseable(mCurrentUserId));
-                if (!isUseable(mCurrentUserId)) {
-                    pw.println("enabled=" + mProvider.getState().enabled);
-                }
-
-                pw.println("properties=" + mProvider.getState().properties);
-            }
-
-            mProvider.dump(fd, pw, args);
-
-            pw.decreaseIndent();
-        }
-
         @GuardedBy("mLock")
         @Override
         public void onReportLocation(Location location) {
@@ -927,18 +879,20 @@
                 // it would be more correct to call this for all users, but we know this can
                 // only affect the current user since providers are disabled for non-current
                 // users
-                onUseableChangedLocked(mCurrentUserId);
+                onUseableChangedLocked(mUserInfoStore.getCurrentUserId());
             }
         }
 
-        @GuardedBy("mLock")
         public boolean isUseable() {
-            return isUseable(mCurrentUserId);
+            return isUseable(mUserInfoStore.getCurrentUserId());
         }
 
-        @GuardedBy("mLock")
         public boolean isUseable(int userId) {
             synchronized (mLock) {
+                // normalize user id to always refer to parent since profile state is always the
+                // same as parent state
+                userId = mUserInfoStore.getParentUserId(userId);
+
                 return mUseable.get(userId, Boolean.FALSE);
             }
         }
@@ -950,15 +904,20 @@
                 return;
             }
 
+            // normalize user id to always refer to parent since profile state is always the same
+            // as parent state
+            userId = mUserInfoStore.getParentUserId(userId);
+
             // if any property that contributes to "useability" here changes state, it MUST result
             // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
             // guarantee that it will always eventually reach the correct state.
-            boolean useable = isCurrentProfileLocked(userId)
+            boolean useable = (userId == mUserInfoStore.getCurrentUserId())
                     && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().enabled;
 
             if (useable == isUseable(userId)) {
                 return;
             }
+
             mUseable.put(userId, useable);
 
             if (D) {
@@ -986,6 +945,30 @@
 
             updateProviderUseableLocked(this);
         }
+
+        public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+            synchronized (mLock) {
+                pw.print(mName + " provider");
+                if (mProvider.isMock()) {
+                    pw.print(" [mock]");
+                }
+                pw.println(":");
+
+                pw.increaseIndent();
+
+                boolean useable = isUseable();
+                pw.println("useable=" + useable);
+                if (!useable) {
+                    pw.println("enabled=" + mProvider.getState().enabled);
+                }
+
+                pw.println("properties=" + mProvider.getState().properties);
+            }
+
+            mProvider.dump(fd, pw, args);
+
+            pw.decreaseIndent();
+        }
     }
 
     class PassiveLocationProviderManager extends LocationProviderManager {
@@ -1626,7 +1609,7 @@
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (!isCurrentProfileLocked(
+                if (!mUserInfoStore.isCurrentUserOrProfile(
                         UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
                     continue;
                 }
@@ -1691,7 +1674,7 @@
             // initialize the low power mode to true and set to false if any of the records requires
             providerRequest.setLowPowerMode(true);
             for (UpdateRecord record : records) {
-                if (!isCurrentProfileLocked(
+                if (!mUserInfoStore.isCurrentUserOrProfile(
                         UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
                     continue;
                 }
@@ -1750,7 +1733,7 @@
                 // TODO: overflow
                 long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (isCurrentProfileLocked(
+                    if (mUserInfoStore.isCurrentUserOrProfile(
                             UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
 
@@ -2243,8 +2226,8 @@
                 if (manager == null) return null;
 
                 // only the current user or location providers may get location this way
-                if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isProviderPackage(
-                        packageName)) {
+                if (!mUserInfoStore.isCurrentUserOrProfile(UserHandle.getUserId(uid))
+                        && !isProviderPackage(packageName)) {
                     return null;
                 }
 
@@ -2773,12 +2756,11 @@
             }
 
             int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid);
-            if (!isCurrentProfileLocked(receiverUserId)
+            if (!mUserInfoStore.isCurrentUserOrProfile(receiverUserId)
                     && !isProviderPackage(receiver.mCallerIdentity.mPackageName)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
-                            " (current user: " + mCurrentUserId + ", app: " +
-                            receiver.mCallerIdentity.mPackageName + ")");
+                            " (app: " + receiver.mCallerIdentity.mPackageName + ")");
                 }
                 continue;
             }
@@ -3028,9 +3010,17 @@
                     + TimeUtils.logTimeOfDay(System.currentTimeMillis()));
             ipw.println(", Current Elapsed Time: "
                     + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
-            ipw.println("Current user: " + mCurrentUserId + " " + Arrays.toString(
-                    mCurrentUserProfiles));
-            ipw.println("Location Mode: " + isLocationEnabledForUser(mCurrentUserId));
+
+            ipw.println("User Info:");
+            ipw.increaseIndent();
+            mUserInfoStore.dump(fd, ipw, args);
+            ipw.decreaseIndent();
+
+            ipw.println("Location Settings:");
+            ipw.increaseIndent();
+            mSettingsStore.dump(fd, ipw, args);
+            ipw.decreaseIndent();
+
             ipw.println("Battery Saver Location Mode: "
                     + locationPowerSaveModeToString(mBatterySaverMode));
 
@@ -3096,21 +3086,14 @@
                 mLocationFudger.dump(fd, ipw, args);
                 ipw.decreaseIndent();
             }
-        }
 
-        ipw.println("Location Settings:");
-        ipw.increaseIndent();
-        mSettingsStore.dump(fd, ipw, args);
-        ipw.decreaseIndent();
+            ipw.println("Location Providers:");
+            ipw.increaseIndent();
+            for (LocationProviderManager manager : mProviderManagers) {
+                manager.dump(fd, ipw, args);
+            }
+            ipw.decreaseIndent();
 
-        ipw.println("Location Providers:");
-        ipw.increaseIndent();
-        for (LocationProviderManager manager : mProviderManagers) {
-            manager.dump(fd, ipw, args);
-        }
-        ipw.decreaseIndent();
-
-        synchronized (mLock) {
             if (mGnssManagerService != null) {
                 ipw.println("GNSS:");
                 ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 0be21c5..2b7745b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -83,7 +83,6 @@
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d7ae5b5..e39d6d5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1305,21 +1305,13 @@
     }
 
     private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) {
-        synchronized (mSyncRoot) {
-            final IBinder token = getDisplayToken(displayId);
-            if (token == null) {
-                return null;
-            }
-            final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId);
-            if (logicalDisplay == null) {
-                return null;
-            }
-
-            final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
-            return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(),
-                    displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(),
-                    false /* useIdentityTransform */, 0 /* rotation */);
+        final IBinder token = getDisplayToken(displayId);
+        if (token == null) {
+            return null;
         }
+        return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
+                        token, new Rect(), 0 /* width */, 0 /* height */,
+                        false /* useIdentityTransform */, 0 /* rotation */);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/location/UserInfoStore.java b/services/core/java/com/android/server/location/UserInfoStore.java
new file mode 100644
index 0000000..550f51c
--- /dev/null
+++ b/services/core/java/com/android/server/location/UserInfoStore.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2020 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.location;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Provides accessors and listeners for all user info.
+ */
+public class UserInfoStore {
+
+    /**
+     * Listener for current user changes.
+     */
+    public interface UserChangedListener {
+        /**
+         * Called when the current user changes.
+         */
+        void onUserChanged(@UserIdInt int oldUserId, @UserIdInt int newUserId);
+    }
+
+    private final Context mContext;
+    private final CopyOnWriteArrayList<UserChangedListener> mListeners;
+
+    @GuardedBy("this")
+    @Nullable
+    private UserManager mUserManager;
+
+    @GuardedBy("this")
+    @UserIdInt
+    private int mCurrentUserId;
+
+    @GuardedBy("this")
+    @UserIdInt
+    private int mCachedParentUserId;
+    @GuardedBy("this")
+    private int[] mCachedProfileUserIds;
+
+    public UserInfoStore(Context context) {
+        mContext = context;
+        mListeners = new CopyOnWriteArrayList<>();
+
+        mCurrentUserId = UserHandle.USER_NULL;
+        mCachedParentUserId = UserHandle.USER_NULL;
+        mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
+    }
+
+    /** Called when system is ready. */
+    public synchronized void onSystemReady() {
+        if (mUserManager != null) {
+            return;
+        }
+
+        mUserManager = mContext.getSystemService(UserManager.class);
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+
+        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_USER_SWITCHED:
+                        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL);
+                        if (userId != UserHandle.USER_NULL) {
+                            onUserChanged(userId);
+                        }
+                        break;
+                    case Intent.ACTION_MANAGED_PROFILE_ADDED:
+                    case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+                        onUserProfilesChanged();
+                        break;
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());
+
+        mCurrentUserId = ActivityManager.getCurrentUser();
+    }
+
+    /**
+     * Adds a listener for user changed events.
+     */
+    public void addListener(UserChangedListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes a listener for user changed events.
+     */
+    public void removeListener(UserChangedListener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void onUserChanged(@UserIdInt int newUserId) {
+        int oldUserId;
+        synchronized (this) {
+            if (newUserId == mCurrentUserId) {
+                return;
+            }
+
+            oldUserId = mCurrentUserId;
+            mCurrentUserId = newUserId;
+        }
+
+        for (UserChangedListener listener : mListeners) {
+            listener.onUserChanged(oldUserId, newUserId);
+        }
+    }
+
+    private synchronized void onUserProfilesChanged() {
+        // this intent is only sent to the current user
+        if (mCachedParentUserId == mCurrentUserId) {
+            mCachedParentUserId = UserHandle.USER_NULL;
+            mCachedProfileUserIds = null;
+        }
+    }
+
+    /**
+     * Returns the user id of the current user.
+     */
+    @UserIdInt
+    public synchronized int getCurrentUserId() {
+        return mCurrentUserId;
+    }
+
+    /**
+     * Returns true if the given user id is either the current user or a profile of the current
+     * user.
+     */
+    public synchronized boolean isCurrentUserOrProfile(@UserIdInt int userId) {
+        return userId == mCurrentUserId || ArrayUtils.contains(
+                getProfileUserIdsForParentUser(mCurrentUserId), userId);
+    }
+
+    /**
+     * Returns the parent user id of the given user id, or the user id itself if the user id either
+     * is a parent or has no profiles.
+     */
+    @UserIdInt
+    public synchronized int getParentUserId(@UserIdInt int userId) {
+        int parentUserId;
+        if (userId == mCachedParentUserId || ArrayUtils.contains(mCachedProfileUserIds, userId)) {
+            parentUserId = mCachedParentUserId;
+        } else {
+            Preconditions.checkState(mUserManager != null);
+
+            UserInfo userInfo = mUserManager.getProfileParent(userId);
+            if (userInfo != null) {
+                parentUserId = userInfo.id;
+            } else {
+                // getProfileParent() returns null if the userId is already the parent...
+                parentUserId = userId;
+            }
+
+            // force profiles into cache
+            getProfileUserIdsForParentUser(parentUserId);
+        }
+
+        return parentUserId;
+    }
+
+    @GuardedBy("this")
+    private int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
+        Preconditions.checkState(mUserManager != null);
+
+        if (Build.IS_DEBUGGABLE) {
+            Preconditions.checkArgument(mUserManager.getProfileParent(parentUserId) == null);
+        }
+
+        if (parentUserId != mCachedParentUserId) {
+            mCachedParentUserId = parentUserId;
+            mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
+        }
+
+        return mCachedProfileUserIds;
+    }
+
+    /**
+     * Dump info for debugging.
+     */
+    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("Current User: " + mCurrentUserId + " " + Arrays.toString(
+                getProfileUserIdsForParentUser(mCurrentUserId)));
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index d2e54f9..46ea9d1 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -25,11 +25,13 @@
 import android.os.ServiceManager;
 import android.os.UserManager;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.RebootEscrowListener;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -109,20 +111,50 @@
     }
 
     void loadRebootEscrowDataIfAvailable() {
-        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
-        if (rebootEscrow == null) {
+        List<UserInfo> users = mUserManager.getUsers();
+        List<UserInfo> rebootEscrowUsers = new ArrayList<>();
+        for (UserInfo user : users) {
+            if (mCallbacks.isUserSecure(user.id) && mStorage.hasRebootEscrow(user.id)) {
+                rebootEscrowUsers.add(user);
+            }
+        }
+
+        if (rebootEscrowUsers.isEmpty()) {
             return;
         }
 
-        final SecretKeySpec escrowKey;
+        SecretKeySpec escrowKey = getAndClearRebootEscrowKey();
+        if (escrowKey == null) {
+            Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
+            for (UserInfo user : users) {
+                mStorage.removeRebootEscrow(user.id);
+            }
+            StatsLog.write(StatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, false);
+            return;
+        }
+
+        boolean allUsersUnlocked = true;
+        for (UserInfo user : rebootEscrowUsers) {
+            allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey);
+        }
+        StatsLog.write(StatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, allUsersUnlocked);
+    }
+
+    private SecretKeySpec getAndClearRebootEscrowKey() {
+        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+        if (rebootEscrow == null) {
+            return null;
+        }
+
         try {
             byte[] escrowKeyBytes = rebootEscrow.retrieveKey();
             if (escrowKeyBytes == null) {
-                return;
+                Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key");
+                return null;
             } else if (escrowKeyBytes.length != 32) {
                 Slog.e(TAG, "IRebootEscrow returned key of incorrect size "
                         + escrowKeyBytes.length);
-                return;
+                return null;
             }
 
             // Make sure we didn't get the null key.
@@ -132,29 +164,22 @@
             }
             if (zero == 0) {
                 Slog.w(TAG, "IRebootEscrow returned an all-zeroes key");
-                return;
+                return null;
             }
 
             // Overwrite the existing key with the null key
             rebootEscrow.storeKey(new byte[32]);
 
-            escrowKey = RebootEscrowData.fromKeyBytes(escrowKeyBytes);
+            return RebootEscrowData.fromKeyBytes(escrowKeyBytes);
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not retrieve escrow data");
-            return;
-        }
-
-        List<UserInfo> users = mUserManager.getUsers();
-        for (UserInfo user : users) {
-            if (mCallbacks.isUserSecure(user.id)) {
-                restoreRebootEscrowForUser(user.id, escrowKey);
-            }
+            return null;
         }
     }
 
-    private void restoreRebootEscrowForUser(@UserIdInt int userId, SecretKeySpec escrowKey) {
+    private boolean restoreRebootEscrowForUser(@UserIdInt int userId, SecretKeySpec escrowKey) {
         if (!mStorage.hasRebootEscrow(userId)) {
-            return;
+            return false;
         }
 
         try {
@@ -165,9 +190,11 @@
 
             mCallbacks.onRebootEscrowRestored(escrowData.getSpVersion(),
                     escrowData.getSyntheticPassword(), userId);
+            return true;
         } catch (IOException e) {
             Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e);
         }
+        return false;
     }
 
     void callToRebootEscrowIfNeeded(@UserIdInt int userId, byte spVersion,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 29338ba0..52750f3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.security.Scrypt;
 import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
@@ -163,16 +164,28 @@
     }
 
     private void syncKeys() throws RemoteException {
+        int generation = mPlatformKeyManager.getGenerationId(mUserId);
         if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
             // Application keys for the user will not be available for sync.
             Log.w(TAG, "Credentials are not set for user " + mUserId);
-            int generation = mPlatformKeyManager.getGenerationId(mUserId);
-            mPlatformKeyManager.invalidatePlatformKey(mUserId, generation);
+            if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED
+                    || mUserId != UserHandle.USER_SYSTEM) {
+                // Only invalidate keys with legacy protection param.
+                mPlatformKeyManager.invalidatePlatformKey(mUserId, generation);
+            }
             return;
         }
         if (isCustomLockScreen()) {
-            Log.w(TAG, "Unsupported credential type " + mCredentialType + "for user " + mUserId);
-            mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(mUserId);
+            Log.w(TAG, "Unsupported credential type " + mCredentialType + " for user " + mUserId);
+            // Keys will be synced when user starts using non custom screen lock.
+            if (generation < PlatformKeyManager.MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED
+                    || mUserId != UserHandle.USER_SYSTEM) {
+                mRecoverableKeyStoreDb.invalidateKeysForUserIdOnCustomScreenLock(mUserId);
+            }
+            return;
+        }
+        if (mPlatformKeyManager.isDeviceLocked(mUserId) && mUserId == UserHandle.USER_SYSTEM) {
+            Log.w(TAG, "Can't sync keys for locked user " + mUserId);
             return;
         }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 0ad6c2a..0761cde 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -67,8 +67,9 @@
  * @hide
  */
 public class PlatformKeyManager {
-    private static final String TAG = "PlatformKeyManager";
+    static final int MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED = 1000000;
 
+    private static final String TAG = "PlatformKeyManager";
     private static final String KEY_ALGORITHM = "AES";
     private static final int KEY_SIZE_BITS = 256;
     private static final String KEY_ALIAS_PREFIX =
@@ -131,14 +132,14 @@
 
     /**
      * Returns {@code true} if the platform key is available. A platform key won't be available if
-     * the user has not set up a lock screen.
+     * device is locked.
      *
      * @param userId The ID of the user to whose lock screen the platform key must be bound.
      *
      * @hide
      */
-    public boolean isAvailable(int userId) {
-        return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId);
+    public boolean isDeviceLocked(int userId) {
+        return mContext.getSystemService(KeyguardManager.class).isDeviceLocked(userId);
     }
 
     /**
@@ -169,7 +170,6 @@
      * @param userId The ID of the user to whose lock screen the platform key must be bound.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
      * @throws KeyStoreException if there is an error in AndroidKeyStore.
-     * @throws InsecureUserException if the user does not have a lock screen set.
      * @throws IOException if there was an issue with local database update.
      * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
      *
@@ -177,13 +177,8 @@
      */
     @VisibleForTesting
     void regenerate(int userId)
-            throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException,
+            throws NoSuchAlgorithmException, KeyStoreException, IOException,
                     RemoteException {
-        if (!isAvailable(userId)) {
-            throw new InsecureUserException(String.format(
-                    Locale.US, "%d does not have a lock screen set.", userId));
-        }
-
         int generationId = getGenerationId(userId);
         int nextId;
         if (generationId == -1) {
@@ -192,6 +187,7 @@
             invalidatePlatformKey(userId, generationId);
             nextId = generationId + 1;
         }
+        generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED);
         generateAndLoadKey(userId, nextId);
     }
 
@@ -203,7 +199,6 @@
      * @throws KeyStoreException if there was an AndroidKeyStore error.
      * @throws UnrecoverableKeyException if the key could not be recovered.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
-     * @throws InsecureUserException if the user does not have a lock screen set.
      * @throws IOException if there was an issue with local database update.
      * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
      *
@@ -211,7 +206,7 @@
      */
     public PlatformEncryptionKey getEncryptKey(int userId)
             throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
-                    InsecureUserException, IOException, RemoteException {
+                    IOException, RemoteException {
         init(userId);
         try {
             // Try to see if the decryption key is still accessible before using the encryption key.
@@ -234,12 +229,11 @@
      * @throws KeyStoreException if there was an AndroidKeyStore error.
      * @throws UnrecoverableKeyException if the key could not be recovered.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
-     * @throws InsecureUserException if the user does not have a lock screen set.
      *
      * @hide
      */
     private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException,
-           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
+            UnrecoverableKeyException, NoSuchAlgorithmException {
         int generationId = getGenerationId(userId);
         String alias = getEncryptAlias(userId, generationId);
         if (!isKeyLoaded(userId, generationId)) {
@@ -258,7 +252,6 @@
      * @throws KeyStoreException if there was an AndroidKeyStore error.
      * @throws UnrecoverableKeyException if the key could not be recovered.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
-     * @throws InsecureUserException if the user does not have a lock screen set.
      * @throws IOException if there was an issue with local database update.
      * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
      *
@@ -266,7 +259,7 @@
      */
     public PlatformDecryptionKey getDecryptKey(int userId)
             throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
-                    InsecureUserException, IOException, RemoteException {
+                    IOException, RemoteException {
         init(userId);
         try {
             PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId);
@@ -288,12 +281,11 @@
      * @throws KeyStoreException if there was an AndroidKeyStore error.
      * @throws UnrecoverableKeyException if the key could not be recovered.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
-     * @throws InsecureUserException if the user does not have a lock screen set.
      *
      * @hide
      */
     private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException,
-           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
+            UnrecoverableKeyException, NoSuchAlgorithmException {
         int generationId = getGenerationId(userId);
         String alias = getDecryptAlias(userId, generationId);
         if (!isKeyLoaded(userId, generationId)) {
@@ -340,13 +332,8 @@
      * @hide
      */
     void init(int userId)
-            throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException,
+            throws KeyStoreException, NoSuchAlgorithmException, IOException,
                     RemoteException {
-        if (!isAvailable(userId)) {
-            throw new InsecureUserException(String.format(
-                    Locale.US, "%d does not have a lock screen set.", userId));
-        }
-
         int generationId = getGenerationId(userId);
         if (isKeyLoaded(userId, generationId)) {
             Log.i(TAG, String.format(
@@ -363,6 +350,7 @@
             generationId++;
         }
 
+        generationId = Math.max(generationId, MIN_GENERATION_ID_FOR_UNLOCKED_DEVICE_REQUIRED);
         generateAndLoadKey(userId, generationId);
     }
 
@@ -440,12 +428,16 @@
 
         KeyProtection.Builder decryptionKeyProtection =
                 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
-                    .setUserAuthenticationRequired(true)
-                    .setUserAuthenticationValidityDurationSeconds(
-                            USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
-        if (userId != UserHandle.USER_SYSTEM) {
+        // Skip UserAuthenticationRequired for main user
+        if (userId ==  UserHandle.USER_SYSTEM) {
+            decryptionKeyProtection.setUnlockedDeviceRequired(true);
+        } else {
+            // With setUnlockedDeviceRequired, KeyStore thinks that device is locked .
+            decryptionKeyProtection.setUserAuthenticationRequired(true);
+            decryptionKeyProtection.setUserAuthenticationValidityDurationSeconds(
+                            USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS);
             // Bind decryption key to secondary profile lock screen secret.
             long secureUserId = getGateKeeperService().getSecureUserId(userId);
             // TODO(b/124095438): Propagate this failure instead of silently failing.
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 383d5cf..6d97ed7 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -19,7 +19,6 @@
 import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
 import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
 import static android.security.keystore.recovery.RecoveryController.ERROR_DOWNGRADE_CERTIFICATE;
-import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
 import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
 import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
 import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
@@ -46,7 +45,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.HexDump;
-import com.android.internal.util.Preconditions;
 import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException;
 import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
 import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException;
@@ -76,8 +74,9 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import javax.crypto.AEADBadTagException;
 
@@ -89,13 +88,14 @@
  */
 public class RecoverableKeyStoreManager {
     private static final String TAG = "RecoverableKeyStoreMgr";
+    private static final long SYNC_DELAY_MILLIS = 2000;
 
     private static RecoverableKeyStoreManager mInstance;
 
     private final Context mContext;
     private final RecoverableKeyStoreDb mDatabase;
     private final RecoverySessionStorage mRecoverySessionStorage;
-    private final ExecutorService mExecutorService;
+    private final ScheduledExecutorService mExecutorService;
     private final RecoverySnapshotListenersStorage mListenersStorage;
     private final RecoverableKeyGenerator mRecoverableKeyGenerator;
     private final RecoverySnapshotStorage mSnapshotStorage;
@@ -136,7 +136,7 @@
                     context.getApplicationContext(),
                     db,
                     new RecoverySessionStorage(),
-                    Executors.newSingleThreadExecutor(),
+                    Executors.newScheduledThreadPool(1),
                     snapshotStorage,
                     new RecoverySnapshotListenersStorage(),
                     platformKeyManager,
@@ -152,7 +152,7 @@
             Context context,
             RecoverableKeyStoreDb recoverableKeyStoreDb,
             RecoverySessionStorage recoverySessionStorage,
-            ExecutorService executorService,
+            ScheduledExecutorService executorService,
             RecoverySnapshotStorage snapshotStorage,
             RecoverySnapshotListenersStorage listenersStorage,
             PlatformKeyManager platformKeyManager,
@@ -724,8 +724,6 @@
             throw new RuntimeException(e);
         } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
-        } catch (InsecureUserException e) {
-            throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
         }
 
         try {
@@ -793,8 +791,6 @@
             throw new RuntimeException(e);
         } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
-        } catch (InsecureUserException e) {
-            throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
         }
 
         try {
@@ -915,7 +911,7 @@
             int storedHashType, @NonNull byte[] credential, int userId) {
         // So as not to block the critical path unlocking the phone, defer to another thread.
         try {
-            mExecutorService.execute(KeySyncTask.newInstance(
+            mExecutorService.schedule(KeySyncTask.newInstance(
                     mContext,
                     mDatabase,
                     mSnapshotStorage,
@@ -923,7 +919,10 @@
                     userId,
                     storedHashType,
                     credential,
-                    /*credentialUpdated=*/ false));
+                    /*credentialUpdated=*/ false),
+                    SYNC_DELAY_MILLIS,
+                    TimeUnit.MILLISECONDS
+            );
         } catch (NoSuchAlgorithmException e) {
             Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e);
         } catch (KeyStoreException e) {
@@ -947,7 +946,7 @@
             int userId) {
         // So as not to block the critical path unlocking the phone, defer to another thread.
         try {
-            mExecutorService.execute(KeySyncTask.newInstance(
+            mExecutorService.schedule(KeySyncTask.newInstance(
                     mContext,
                     mDatabase,
                     mSnapshotStorage,
@@ -955,7 +954,10 @@
                     userId,
                     storedHashType,
                     credential,
-                    /*credentialUpdated=*/ true));
+                    /*credentialUpdated=*/ true),
+                    SYNC_DELAY_MILLIS,
+                    TimeUnit.MILLISECONDS
+            );
         } catch (NoSuchAlgorithmException e) {
             Log.wtf(TAG, "Should never happen - algorithm unavailable for KeySync", e);
         } catch (KeyStoreException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5eafb41..0e08033 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1010,12 +1010,14 @@
             if (clearEffects) {
                 clearEffects();
             }
+            mAssistants.onPanelRevealed(items);
         }
 
         @Override
         public void onPanelHidden() {
             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
             EventLogTags.writeNotificationPanelHidden();
+            mAssistants.onPanelHidden();
         }
 
         @Override
@@ -1062,6 +1064,7 @@
                         reportSeen(r);
                     }
                     r.setVisibility(true, nv.rank, nv.count);
+                    mAssistants.notifyAssistantVisibilityChangedLocked(r.sbn, true);
                     boolean isHun = (nv.location
                             == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
@@ -1080,6 +1083,7 @@
                     NotificationRecord r = mNotificationsByKey.get(nv.key);
                     if (r == null) continue;
                     r.setVisibility(false, nv.rank, nv.count);
+                    mAssistants.notifyAssistantVisibilityChangedLocked(r.sbn, false);
                     nv.recycle();
                 }
             }
@@ -8346,6 +8350,32 @@
             }
         }
 
+        protected void onPanelRevealed(int items) {
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> {
+                    final INotificationListener assistant = (INotificationListener) info.service;
+                    try {
+                        assistant.onPanelRevealed(items);
+                    } catch (RemoteException ex) {
+                        Slog.e(TAG, "unable to notify assistant (panel revealed): " + info, ex);
+                    }
+                });
+            }
+        }
+
+        protected void onPanelHidden() {
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> {
+                    final INotificationListener assistant = (INotificationListener) info.service;
+                    try {
+                        assistant.onPanelHidden();
+                    } catch (RemoteException ex) {
+                        Slog.e(TAG, "unable to notify assistant (panel hidden): " + info, ex);
+                    }
+                });
+            }
+        }
+
         boolean hasUserSet(int userId) {
             synchronized (mLock) {
                 return mUserSetMap.getOrDefault(userId, false);
@@ -8413,6 +8443,24 @@
         }
 
         @GuardedBy("mNotificationLock")
+        void notifyAssistantVisibilityChangedLocked(
+                final StatusBarNotification sbn,
+                final boolean isVisible) {
+            final String key = sbn.getKey();
+            Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key);
+            notifyAssistantLocked(
+                    sbn,
+                    false /* sameUserOnly */,
+                    (assistant, sbnHolder) -> {
+                        try {
+                            assistant.onNotificationVisibilityChanged(key, isVisible);
+                        } catch (RemoteException ex) {
+                            Slog.e(TAG, "unable to notify assistant (visible): " + assistant, ex);
+                        }
+                    });
+        }
+
+        @GuardedBy("mNotificationLock")
         void notifyAssistantExpansionChangedLocked(
                 final StatusBarNotification sbn,
                 final boolean isUserAction,
diff --git a/services/core/java/com/android/server/om/TEST_MAPPING b/services/core/java/com/android/server/om/TEST_MAPPING
new file mode 100644
index 0000000..52163a0
--- /dev/null
+++ b/services/core/java/com/android/server/om/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.om."
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 307a07b..a009183 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,10 +32,13 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.sysprop.ApexProperties;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Singleton;
 import android.util.Slog;
 
@@ -44,15 +47,20 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 
+import com.google.android.collect.Lists;
+
 import java.io.File;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -97,12 +105,27 @@
      * Minimal information about APEX mount points and the original APEX package they refer to.
      */
     static class ActiveApexInfo {
+        @Nullable public final String apexModuleName;
         public final File apexDirectory;
-        public final File preinstalledApexPath;
+        public final File preInstalledApexPath;
 
-        private ActiveApexInfo(File apexDirectory, File preinstalledApexPath) {
+        private ActiveApexInfo(File apexDirectory, File preInstalledApexPath) {
+            this(null, apexDirectory, preInstalledApexPath);
+        }
+
+        private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
+                File preInstalledApexPath) {
+            this.apexModuleName = apexModuleName;
             this.apexDirectory = apexDirectory;
-            this.preinstalledApexPath = preinstalledApexPath;
+            this.preInstalledApexPath = preInstalledApexPath;
+        }
+
+        private ActiveApexInfo(ApexInfo apexInfo) {
+            this(
+                    apexInfo.moduleName,
+                    new File(Environment.getApexDirectory() + File.separator
+                            + apexInfo.moduleName),
+                    new File(apexInfo.preinstalledModulePath));
         }
     }
 
@@ -232,6 +255,17 @@
     abstract boolean uninstallApex(String apexPackagePath);
 
     /**
+     * Registers an APK package as an embedded apk of apex.
+     */
+    abstract void registerApkInApex(AndroidPackage pkg);
+
+    /**
+     * Returns list of {@code packageName} of apks inside the given apex.
+     * @param apexPackageName Package name of the apk container of apex
+     */
+    abstract List<String> getApksInApex(String apexPackageName);
+
+    /**
      * Dumps various state information to the provided {@link PrintWriter} object.
      *
      * @param pw the {@link PrintWriter} object to send information to.
@@ -255,16 +289,33 @@
     static class ApexManagerImpl extends ApexManager {
         private final IApexService mApexService;
         private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private Set<ActiveApexInfo> mActiveApexInfosCache;
+
         /**
-         * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
-         * AndroidManifest.xml}
-         *
-         * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
-         * AndroidManifest.xml}.
-          */
+         * Contains the list of {@code packageName}s of apks-in-apex for given
+         * {@code apexModuleName}. See {@link #mPackageNameToApexModuleName} to understand the
+         * difference between {@code packageName} and {@code apexModuleName}.
+         */
+        @GuardedBy("mLock")
+        private Map<String, List<String>> mApksInApex = new ArrayMap<>();
+
         @GuardedBy("mLock")
         private List<PackageInfo> mAllPackagesCache;
 
+        /**
+         * An APEX is a file format that delivers the apex-payload wrapped in an apk container. The
+         * apk container has a reference name, called {@code packageName}, which is found inside the
+         * {@code AndroidManifest.xml}. The apex payload inside the container also has a reference
+         * name, called {@code apexModuleName}, which is found in {@code apex_manifest.json} file.
+         *
+         * {@link #mPackageNameToApexModuleName} contains the mapping from {@code packageName} of
+         * the apk container to {@code apexModuleName} of the apex-payload inside.
+         */
+        @GuardedBy("mLock")
+        private Map<String, String> mPackageNameToApexModuleName;
+
         ApexManagerImpl(IApexService apexService) {
             mApexService = apexService;
         }
@@ -291,18 +342,25 @@
 
         @Override
         List<ActiveApexInfo> getActiveApexInfos() {
-            try {
-                return Arrays.stream(mApexService.getActivePackages())
-                        .map(apexInfo -> new ActiveApexInfo(
-                                new File(
-                                Environment.getApexDirectory() + File.separator
-                                        + apexInfo.moduleName),
-                                new File(apexInfo.preinstalledModulePath))).collect(
-                                Collectors.toList());
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
+            synchronized (mLock) {
+                if (mActiveApexInfosCache == null) {
+                    try {
+                        mActiveApexInfosCache = new ArraySet<>();
+                        final ApexInfo[] activePackages = mApexService.getActivePackages();
+                        for (int i = 0; i < activePackages.length; i++) {
+                            ApexInfo apexInfo = activePackages[i];
+                            mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
+                    }
+                }
+                if (mActiveApexInfosCache != null) {
+                    return new ArrayList<>(mActiveApexInfosCache);
+                } else {
+                    return Collections.emptyList();
+                }
             }
-            return Collections.emptyList();
         }
 
         @Override
@@ -325,6 +383,7 @@
                 }
                 try {
                     mAllPackagesCache = new ArrayList<>();
+                    mPackageNameToApexModuleName = new HashMap<>();
                     HashSet<String> activePackagesSet = new HashSet<>();
                     HashSet<String> factoryPackagesSet = new HashSet<>();
                     final ApexInfo[] allPkgs = mApexService.getAllPackages();
@@ -350,6 +409,7 @@
                         final PackageInfo packageInfo =
                                 PackageParser.generatePackageInfo(pkg, ai, flags);
                         mAllPackagesCache.add(packageInfo);
+                        mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
                         if (ai.isActive) {
                             if (activePackagesSet.contains(packageInfo.packageName)) {
                                 throw new IllegalStateException(
@@ -366,7 +426,6 @@
                             }
                             factoryPackagesSet.add(packageInfo.packageName);
                         }
-
                     }
                 } catch (RemoteException re) {
                     Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
@@ -533,6 +592,37 @@
             }
         }
 
+        @Override
+        void registerApkInApex(AndroidPackage pkg) {
+            synchronized (mLock) {
+                final Iterator<ActiveApexInfo> it = mActiveApexInfosCache.iterator();
+                while (it.hasNext()) {
+                    final ActiveApexInfo aai = it.next();
+                    if (pkg.getBaseCodePath().startsWith(aai.apexDirectory.getAbsolutePath())) {
+                        List<String> apks = mApksInApex.get(aai.apexModuleName);
+                        if (apks == null) {
+                            apks = Lists.newArrayList();
+                            mApksInApex.put(aai.apexModuleName, apks);
+                        }
+                        apks.add(pkg.getPackageName());
+                    }
+                }
+            }
+        }
+
+        @Override
+        List<String> getApksInApex(String apexPackageName) {
+            // TODO(b/142712057): Avoid calling populateAllPackagesCacheIfNeeded during boot.
+            populateAllPackagesCacheIfNeeded();
+            synchronized (mLock) {
+                String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
+                if (moduleName == null) {
+                    return Collections.emptyList();
+                }
+                return mApksInApex.getOrDefault(moduleName, Collections.emptyList());
+            }
+        }
+
         /**
          * Dump information about the packages contained in a particular cache
          * @param packagesCache the cache to print information about.
@@ -614,7 +704,6 @@
      * updating APEX packages.
      */
     private static final class ApexManagerFlattenedApex extends ApexManager {
-
         @Override
         List<ActiveApexInfo> getActiveApexInfos() {
             // There is no apexd running in case of flattened apex
@@ -721,6 +810,16 @@
         }
 
         @Override
+        void registerApkInApex(AndroidPackage pkg) {
+            // No-op
+        }
+
+        @Override
+        List<String> getApksInApex(String apexPackageName) {
+            return Collections.emptyList();
+        }
+
+        @Override
         void dump(PrintWriter pw, String packageName) {
             // No-op
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index c43f234..6331dd4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -188,7 +188,7 @@
         }
     };
 
-    public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
+    public PackageInstallerService(Context context, PackageManagerService pm) {
         mContext = context;
         mPm = pm;
         mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -206,9 +206,8 @@
         mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
         mSessionsDir.mkdirs();
 
-        mApexManager = am;
-
-        mStagingManager = new StagingManager(this, am, context);
+        mApexManager = ApexManager.getInstance();
+        mStagingManager = new StagingManager(this, context);
     }
 
     boolean okToSendBroadcasts()  {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 97a2d43..165bdeb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2413,16 +2413,6 @@
 
     @Override
     public void addFile(String name, long lengthBytes, byte[] metadata) {
-        if (mIncrementalFileStorages != null) {
-            try {
-                mIncrementalFileStorages.addFile(new InstallationFile(name, lengthBytes, metadata));
-                //TODO(b/136132412): merge incremental and callback installation schemes
-                return;
-            } catch (IOException ex) {
-                throw new IllegalStateException(
-                        "Failed to add and configure Incremental File: " + name, ex);
-            }
-        }
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
                     "Cannot add files to non-data loader installation session.");
@@ -2435,7 +2425,6 @@
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotSealedLocked("addFile");
-
             mFiles.add(FileInfo.added(name, lengthBytes, metadata));
         }
     }
@@ -2486,7 +2475,7 @@
      */
     private void prepareDataLoader()
             throws PackageManagerException, StreamingException {
-        if (!isStreamingInstallation()) {
+        if (!isDataLoaderInstallation()) {
             return;
         }
 
@@ -2500,6 +2489,18 @@
                     file -> file.name.substring(
                             0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect(
                 Collectors.toList());
+        if (mIncrementalFileStorages != null) {
+            for (InstallationFile file : addedFiles) {
+                try {
+                    mIncrementalFileStorages.addFile(file);
+                } catch (IOException ex) {
+                    // TODO(b/146080380): add incremental-specific error code
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Failed to add and configure Incremental File: " + file.getName(), ex);
+                }
+            }
+            return;
+        }
 
         final FileSystemConnector connector = new FileSystemConnector(addedFiles);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 24180f2..17870eb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -492,6 +492,7 @@
     static final int SCAN_AS_PRODUCT = 1 << 20;
     static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
     static final int SCAN_AS_ODM = 1 << 22;
+    static final int SCAN_AS_APK_IN_APEX = 1 << 23;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -2589,6 +2590,9 @@
                     & (SCAN_AS_VENDOR | SCAN_AS_ODM | SCAN_AS_PRODUCT | SCAN_AS_SYSTEM_EXT)) != 0) {
                 return true;
             }
+            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+                return true;
+            }
             return false;
         }
 
@@ -3332,7 +3336,7 @@
                 }
             }
 
-            mInstallerService = new PackageInstallerService(mContext, this, mApexManager);
+            mInstallerService = new PackageInstallerService(mContext, this);
             final Pair<ComponentName, String> instantAppResolverComponent =
                     getInstantAppResolverLPr();
             if (instantAppResolverComponent != null) {
@@ -11713,6 +11717,9 @@
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
             // Add the new setting to mPackages
             mPackages.put(pkg.getAppInfoPackageName(), pkg);
+            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+                mApexManager.registerApkInApex(pkg);
+            }
 
             // Add the package's KeySets to the global KeySetManagerService
             KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -17760,10 +17767,10 @@
             ApexManager.ActiveApexInfo apexInfo) {
         for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
             SystemPartition sp = SYSTEM_PARTITIONS.get(i);
-            if (apexInfo.preinstalledApexPath.getAbsolutePath().startsWith(
+            if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
                     sp.folder.getAbsolutePath())) {
-                return new SystemPartition(apexInfo.apexDirectory, sp.scanFlag,
-                        false /* hasOverlays */);
+                return new SystemPartition(apexInfo.apexDirectory,
+                        sp.scanFlag | SCAN_AS_APK_IN_APEX, false /* hasOverlays */);
             }
         }
         return null;
@@ -22793,7 +22800,7 @@
             ArrayList<String> systemPackageNames = new ArrayList<>(pkgNames.length);
 
             for (String pkgName: pkgNames) {
-                synchronized (mPackages) {
+                synchronized (mLock) {
                     if (pkgName == null) {
                         continue;
                     }
@@ -23454,6 +23461,11 @@
         }
 
         @Override
+        public List<String> getApksInApex(String apexPackageName) {
+            return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName);
+        }
+
+        @Override
         public void uninstallApex(String packageName, long versionCode, int userId,
                 IntentSender intentSender, int flags) {
             final int callerUid = Binder.getCallingUid();
@@ -23634,7 +23646,7 @@
 
     @Nullable
     public PackageSetting getPackageSetting(String packageName) {
-        synchronized (mPackages) {
+        synchronized (mLock) {
             packageName = resolveInternalPackageNameLPr(
                     packageName, PackageManager.VERSION_CODE_HIGHEST);
             return mSettings.mPackages.get(packageName);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9e462cd..2265d01 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -33,11 +33,13 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.ParceledListSlice;
+import android.content.pm.parsing.AndroidPackage;
 import android.content.rollback.IRollbackManager;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
@@ -50,6 +52,8 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.util.IntArray;
@@ -61,6 +65,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.BackgroundThread;
+import com.android.server.LocalServices;
 
 import java.io.File;
 import java.io.IOException;
@@ -93,10 +98,11 @@
     @GuardedBy("mStagedSessions")
     private final SparseIntArray mSessionRollbackIds = new SparseIntArray();
 
-    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
+    StagingManager(PackageInstallerService pi, Context context) {
         mPi = pi;
-        mApexManager = am;
         mContext = context;
+
+        mApexManager = ApexManager.getInstance();
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mPreRebootVerificationHandler = new PreRebootVerificationHandler(
                 BackgroundThread.get().getLooper());
@@ -334,6 +340,88 @@
         return PackageHelper.getStorageManager().needsCheckpoint();
     }
 
+    /**
+     * Apks inside apex are not installed using apk-install flow. They are scanned from the system
+     * directory directly by PackageManager, as such, RollbackManager need to handle their data
+     * separately here.
+     */
+    private void snapshotAndRestoreApkInApexUserData(PackageInstallerSession session) {
+        // We want to process apks inside apex. So current session needs to contain apex.
+        if (!sessionContainsApex(session)) {
+            return;
+        }
+
+        boolean doSnapshotOrRestore =
+                (session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
+                || session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+        if (!doSnapshotOrRestore) {
+            return;
+        }
+
+        // Find all the apex sessions that needs processing
+        List<PackageInstallerSession> apexSessions = new ArrayList<>();
+        if (session.isMultiPackage()) {
+            List<PackageInstallerSession> childrenSessions = new ArrayList<>();
+            synchronized (mStagedSessions) {
+                for (int childSessionId : session.getChildSessionIds()) {
+                    PackageInstallerSession childSession = mStagedSessions.get(childSessionId);
+                    if (childSession != null) {
+                        childrenSessions.add(childSession);
+                    }
+                }
+            }
+            for (PackageInstallerSession childSession : childrenSessions) {
+                if (sessionContainsApex(childSession)) {
+                    apexSessions.add(childSession);
+                }
+            }
+        } else {
+            apexSessions.add(session);
+        }
+
+        // For each apex, process the apks inside it
+        for (PackageInstallerSession apexSession : apexSessions) {
+            List<String> apksInApex = mApexManager.getApksInApex(apexSession.getPackageName());
+            for (String apk: apksInApex) {
+                snapshotAndRestoreApkInApexUserData(apk);
+            }
+        }
+    }
+
+    private void snapshotAndRestoreApkInApexUserData(String packageName) {
+        IRollbackManager rm = IRollbackManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ROLLBACK_SERVICE));
+
+        PackageManagerInternal mPmi = LocalServices.getService(PackageManagerInternal.class);
+        AndroidPackage pkg = mPmi.getPackage(packageName);
+        if (pkg == null) {
+            Slog.e(TAG, "Could not find package: " + packageName
+                    + "for snapshotting/restoring user data.");
+            return;
+        }
+        final String seInfo = pkg.getSeInfo();
+        final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+        final int[] allUsers = um.getUserIds();
+
+        int appId = -1;
+        long ceDataInode = -1;
+        final PackageSetting ps = (PackageSetting) mPmi.getPackageSetting(packageName);
+        if (ps != null && rm != null) {
+            appId = ps.appId;
+            ceDataInode = ps.getCeDataInode(UserHandle.USER_SYSTEM);
+            // NOTE: We ignore the user specified in the InstallParam because we know this is
+            // an update, and hence need to restore data for all installed users.
+            final int[] installedUsers = ps.queryInstalledUsers(allUsers, true);
+
+            try {
+                rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
+                        seInfo, 0 /*token*/);
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Error snapshotting/restoring user data: " + re);
+            }
+        }
+    }
+
     private void resumeSession(@NonNull PackageInstallerSession session) {
         Slog.d(TAG, "Resuming session " + session.sessionId);
 
@@ -407,6 +495,7 @@
                 abortCheckpoint();
                 return;
             }
+            snapshotAndRestoreApkInApexUserData(session);
             Slog.i(TAG, "APEX packages in session " + session.sessionId
                     + " were successfully activated. Proceeding with APK packages, if any");
         }
@@ -529,7 +618,7 @@
                         Arrays.stream(session.getChildSessionIds())
                                 // Retrieve cached sessions matching ids.
                                 .mapToObj(i -> mStagedSessions.get(i))
-                                // Filter only the ones containing APKs.s
+                                // Filter only the ones containing APKs.
                                 .filter(childSession -> !isApexSession(childSession))
                                 .collect(Collectors.toList());
             }
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 88c1564..9f592b8 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -62,7 +62,7 @@
 
     private static final String TAG = "RollbackManager";
 
-    @IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
+    @IntDef(prefix = { "ROLLBACK_STATE_" }, value = {
             ROLLBACK_STATE_ENABLING,
             ROLLBACK_STATE_AVAILABLE,
             ROLLBACK_STATE_COMMITTED,
@@ -92,6 +92,19 @@
      */
     static final int ROLLBACK_STATE_DELETED = 4;
 
+    @IntDef(flag = true, prefix = { "MATCH_" }, value = {
+            MATCH_APK_IN_APEX,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RollbackInfoFlags {}
+
+    /**
+     * {@link RollbackInfo} flag: include {@code RollbackInfo} packages that are apk-in-apex.
+     * These packages do not have their own sessions. They are embedded in an apex which has a
+     * session id.
+     */
+    static final int MATCH_APK_IN_APEX = 1;
+
     /**
      * The session ID for the staged session if this rollback data represents a staged session,
      * {@code -1} otherwise.
@@ -323,8 +336,8 @@
                 new VersionedPackage(packageName, newVersion),
                 new VersionedPackage(packageName, installedVersion),
                 new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
-                isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */,
-                rollbackDataPolicy);
+                isApex, false /* isApkInApex */, new IntArray(),
+                new SparseLongArray() /* ceSnapshotInodes */, rollbackDataPolicy);
 
         synchronized (mLock) {
             info.getPackages().add(packageRollbackInfo);
@@ -334,6 +347,30 @@
     }
 
     /**
+     * Enables this rollback for the provided apk-in-apex.
+     *
+     * @return boolean True if the rollback was enabled successfully for the specified package.
+     */
+    boolean enableForPackageInApex(String packageName, long installedVersion,
+            int rollbackDataPolicy) {
+        // TODO(b/142712057): Extract the new version number of apk-in-apex
+        // The new version for the apk-in-apex is set to 0 for now. If the package is then further
+        // updated via non-staged install flow, then RollbackManagerServiceImpl#onPackageReplaced()
+        // will be called and this rollback will be deleted. Other ways of package update have not
+        // been handled yet.
+        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
+                new VersionedPackage(packageName, 0 /* newVersion */),
+                new VersionedPackage(packageName, installedVersion),
+                new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
+                false /* isApex */, true /* isApkInApex */, new IntArray(),
+                new SparseLongArray() /* ceSnapshotInodes */, rollbackDataPolicy);
+        synchronized (mLock) {
+            info.getPackages().add(packageRollbackInfo);
+        }
+        return true;
+    }
+
+    /**
      * Snapshots user data for the provided package and user ids. Does nothing if this rollback is
      * not in the ENABLING state.
      */
@@ -428,6 +465,11 @@
                         parentSessionId);
 
                 for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                    if (pkgRollbackInfo.isApkInApex()) {
+                        // No need to issue a downgrade install request for apk-in-apex. It will
+                        // be rolled back when its parent apex is downgraded.
+                        continue;
+                    }
                     PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                             PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                     String installerPackageName = mInstallerPackageName;
@@ -453,7 +495,8 @@
                             this, pkgRollbackInfo.getPackageName());
                     if (packageCodePaths == null) {
                         sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
-                                "Backup copy of package inaccessible");
+                                "Backup copy of package: "
+                                        + pkgRollbackInfo.getPackageName() + " is inaccessible");
                         return;
                     }
 
@@ -696,9 +739,30 @@
         }
     }
 
-    int getPackageCount() {
+    /**
+     * Returns the number of {@link PackageRollbackInfo} we are storing in this {@link Rollback}
+     * instance. By default, this method does not include apk-in-apex package in the count.
+     *
+     * @param flags Apk-in-apex packages can be included in the count by passing
+     * {@link Rollback#MATCH_APK_IN_APEX}
+     *
+     * @return Counts number of {@link PackageRollbackInfo} stored in the {@link Rollback}
+     * according to {@code flags} passed
+     */
+    int getPackageCount(@RollbackInfoFlags int flags) {
         synchronized (mLock) {
-            return info.getPackages().size();
+            List<PackageRollbackInfo> packages = info.getPackages();
+            if ((flags & MATCH_APK_IN_APEX) != 0) {
+                return packages.size();
+            }
+
+            int packagesWithoutApkInApex = 0;
+            for (PackageRollbackInfo rollbackInfo : packages) {
+                if (!rollbackInfo.isApkInApex()) {
+                    packagesWithoutApkInApex++;
+                }
+            }
+            return packagesWithoutApkInApex;
         }
     }
 
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e29d1a7..8f8a5c4 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -891,9 +891,36 @@
         }
 
         ApplicationInfo appInfo = pkgInfo.applicationInfo;
-        return rollback.enableForPackage(packageName, newPackage.versionCode,
+        boolean success = rollback.enableForPackage(packageName, newPackage.versionCode,
                 pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir,
                 appInfo.splitSourceDirs, session.rollbackDataPolicy);
+        if (!success) {
+            return success;
+        }
+
+        if (isApex) {
+            // Check if this apex contains apks inside it. If true, then they should be added as
+            // a RollbackPackageInfo into this rollback
+            final PackageManagerInternal pmi = LocalServices.getService(
+                    PackageManagerInternal.class);
+            List<String> apksInApex = pmi.getApksInApex(packageName);
+            for (String apkInApex : apksInApex) {
+                // Get information about the currently installed package.
+                final PackageInfo apkPkgInfo;
+                try {
+                    apkPkgInfo = getPackageInfo(apkInApex);
+                } catch (PackageManager.NameNotFoundException e) {
+                    // TODO: Support rolling back fresh package installs rather than
+                    // fail here. Test this case.
+                    Slog.e(TAG, apkInApex + " is not installed");
+                    return false;
+                }
+                success = rollback.enableForPackageInApex(
+                        apkInApex, apkPkgInfo.getLongVersionCode(), session.rollbackDataPolicy);
+                if (!success) return success;
+            }
+        }
+        return true;
     }
 
     @Override
@@ -907,9 +934,13 @@
         getHandler().post(() -> {
             snapshotUserDataInternal(packageName, userIds);
             restoreUserDataInternal(packageName, userIds, appId, seInfo);
-            final PackageManagerInternal pmi = LocalServices.getService(
-                    PackageManagerInternal.class);
-            pmi.finishPackageInstall(token, false);
+            // When this method is called as part of the install flow, a positive token number is
+            // passed to it. Need to notify the PackageManager when we are done.
+            if (token > 0) {
+                final PackageManagerInternal pmi = LocalServices.getService(
+                        PackageManagerInternal.class);
+                pmi.finishPackageInstall(token, false);
+            }
         });
     }
 
@@ -1195,7 +1226,11 @@
             return null;
         }
 
-        if (rollback.getPackageCount() != newRollback.getPackageSessionIdCount()) {
+        // We are checking if number of packages (excluding apk-in-apex) we enabled for rollback is
+        // equal to the number of sessions we are installing, to ensure we didn't skip enabling
+        // of any sessions. If we successfully enable an apex, then we can assume we enabled
+        // rollback for the embedded apk-in-apex, if any.
+        if (rollback.getPackageCount(0 /*flags*/) != newRollback.getPackageSessionIdCount()) {
             Slog.e(TAG, "Failed to enable rollback for all packages in session.");
             rollback.delete(mAppDataRollbackHelper);
             return null;
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index df75a29..bbcd0de 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -341,6 +341,7 @@
         json.put("pendingRestores", convertToJsonArray(pendingRestores));
 
         json.put("isApex", info.isApex());
+        json.put("isApkInApex", info.isApkInApex());
 
         // Field is named 'installedUsers' for legacy reasons.
         json.put("installedUsers", convertToJsonArray(snapshottedUsers));
@@ -364,6 +365,7 @@
                 json.getJSONArray("pendingRestores"));
 
         final boolean isApex = json.getBoolean("isApex");
+        final boolean isApkInApex = json.getBoolean("isApkInApex");
 
         // Field is named 'installedUsers' for legacy reasons.
         final IntArray snapshottedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
@@ -375,8 +377,8 @@
                 PackageManager.RollbackDataPolicy.RESTORE);
 
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
-                pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes,
-                rollbackDataPolicy);
+                pendingBackups, pendingRestores, isApex, isApkInApex, snapshottedUsers,
+                ceSnapshotInodes, rollbackDataPolicy);
     }
 
     private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java
index e367f28..a75f1c2 100644
--- a/services/core/java/com/android/server/stats/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java
@@ -16,11 +16,166 @@
 
 package com.android.server.stats;
 
-import android.content.Context;
-import android.util.Slog;
+import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.getUidForPid;
+import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
+import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
 
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
+import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.ProcfsMemoryUtil.forEachPid;
+import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
+import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalOpsRequest;
+import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.INotificationManager;
+import android.app.ProcessMemoryState;
+import android.app.StatsManager;
+import android.app.StatsManager.PullAtomMetadata;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.UidTraffic;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.NetworkStats;
+import android.net.wifi.WifiManager;
+import android.os.BatteryStats;
+import android.os.BatteryStatsInternal;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.CoolingDevice;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IPullAtomCallback;
+import android.os.IStatsCompanionService;
+import android.os.IStatsd;
+import android.os.IStoraged;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+import android.os.StatsLogEventWrapper;
+import android.os.SynchronousResultReceiver;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Temperature;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.connectivity.WifiActivityEnergyInfo;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.provider.Settings;
+import android.stats.storage.StorageEnums;
+import android.telephony.ModemActivityInfo;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.StatsEvent;
+import android.util.StatsLog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.procstats.IProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.internal.os.BinderCallsStats.ExportedCallStat;
+import com.android.internal.os.KernelCpuSpeedReader;
+import com.android.internal.os.KernelCpuThreadReader;
+import com.android.internal.os.KernelCpuThreadReaderDiff;
+import com.android.internal.os.KernelCpuThreadReaderSettingsObserver;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
+import com.android.internal.os.KernelWakelockReader;
+import com.android.internal.os.KernelWakelockStats;
+import com.android.internal.os.LooperStats;
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.StoragedUidIoStatsReader;
+import com.android.internal.util.DumpUtils;
+import com.android.server.BinderCallsStatsService;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
+import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.notification.NotificationManagerService;
+import com.android.server.role.RoleManagerInternal;
+import com.android.server.stats.IonMemoryUtil.IonAllocations;
+import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.server.storage.DiskStatsFileLogger;
+import com.android.server.storage.DiskStatsLoggingService;
+
+import com.google.android.collect.Sets;
+
+import libcore.io.IoUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * SystemService containing PullAtomCallbacks that are registered with statsd.
@@ -31,13 +186,24 @@
     private static final String TAG = "StatsPullAtomService";
     private static final boolean DEBUG = true;
 
+    private final Object mNetworkStatsLock = new Object();
+    @GuardedBy("mNetworkStatsLock")
+    private INetworkStatsService mNetworkStatsService;
+    private final Object mThermalLock = new Object();
+    @GuardedBy("mThermalLock")
+    private IThermalService mThermalService;
+
+    private final Context mContext;
+    private StatsManager mStatsManager;
+
     public StatsPullAtomService(Context context) {
         super(context);
+        mContext = context;
     }
 
     @Override
     public void onStart() {
-        // No op.
+        mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER);
     }
 
     @Override
@@ -54,5 +220,621 @@
         if (DEBUG) {
             Slog.d(TAG, "Registering all pullers with statsd");
         }
+        registerWifiBytesTransfer();
+        registerWifiBytesTransferBackground();
+        registerMobileBytesTransfer();
+        registerMobileBytesTransferBackground();
+        registerBluetoothBytesTransfer();
+        registerKernelWakelock();
+        registerCpuTimePerFreq();
+        registerCpuTimePerUid();
+        registerCpuTimePerUidFreq();
+        registerCpuActiveTime();
+        registerCpuClusterTime();
+        registerWifiActivityInfo();
+        registerModemActivityInfo();
+        registerBluetoothActivityInfo();
+        registerSystemElapsedRealtime();
+        registerSystemUptime();
+        registerRemainingBatteryCapacity();
+        registerFullBatteryCapacity();
+        registerBatteryVoltage();
+        registerBatteryLevel();
+        registerBatteryCycleCount();
+        registerProcessMemoryState();
+        registerProcessMemoryHighWaterMark();
+        registerProcessMemorySnapshot();
+        registerSystemIonHeapSize();
+        registerProcessSystemIonHeapSize();
+        registerTemperature();
+        registerCoolingDevice();
+        registerBinderCalls();
+        registerBinderCallsExceptions();
+        registerLooperStats();
+        registerDiskStats();
+        registerDirectoryUsage();
+        registerAppSize();
+        registerCategorySize();
+        registerNumFingerprintsEnrolled();
+        registerNumFacesEnrolled();
+        registerProcStats();
+        registerProcStatsPkgProc();
+        registerDiskIO();
+        registerPowerProfile();
+        registerProcessCpuTime();
+        registerCpuTimePerThreadFreq();
+        registerDeviceCalculatedPowerUse();
+        registerDeviceCalculatedPowerBlameUid();
+        registerDeviceCalculatedPowerBlameOther();
+        registerDebugElapsedClock();
+        registerDebugFailingElapsedClock();
+        registerBuildInformation();
+        registerRoleHolder();
+        registerDangerousPermissionState();
+        registerTimeZoneDataInfo();
+        registerExternalStorageInfo();
+        registerAppsOnExternalStorageInfo();
+        registerFaceSettings();
+        registerAppOps();
+        registerNotificationRemoteViews();
+        registerDangerousPermissionState();
+        registerDangerousPermissionStateSampled();
+    }
+
+    private INetworkStatsService getINetworkStatsService() {
+        synchronized (mNetworkStatsLock) {
+            if (mNetworkStatsService == null) {
+                mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+                        ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+                if (mNetworkStatsService != null) {
+                    try {
+                        mNetworkStatsService.asBinder().linkToDeath(() -> {
+                            synchronized (mNetworkStatsLock) {
+                                mNetworkStatsService = null;
+                            }
+                        }, /* flags */ 0);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "linkToDeath with NetworkStatsService failed", e);
+                        mNetworkStatsService = null;
+                    }
+                }
+
+            }
+            return mNetworkStatsService;
+        }
+    }
+
+    private IThermalService getIThermalService() {
+        synchronized (mThermalLock) {
+            if (mThermalService == null) {
+                mThermalService = IThermalService.Stub.asInterface(
+                        ServiceManager.getService(Context.THERMAL_SERVICE));
+                if (mThermalService != null) {
+                    try {
+                        mThermalService.asBinder().linkToDeath(() -> {
+                            synchronized (mThermalLock) {
+                                mThermalService = null;
+                            }
+                        }, /* flags */ 0);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "linkToDeath with thermalService failed", e);
+                        mThermalService = null;
+                    }
+                }
+            }
+            return mThermalService;
+        }
+    }
+    private void registerWifiBytesTransfer() {
+        int tagId = StatsLog.WIFI_BYTES_TRANSFER;
+        PullAtomMetadata metaData = PullAtomMetadata.newBuilder()
+                .setAdditiveFields(new int[] {2, 3, 4, 5}).build();
+        mStatsManager.registerPullAtomCallback(
+                tagId,
+                metaData,
+                (atomTag, data) -> pullWifiBytesTransfer(atomTag, data),
+                Executors.newSingleThreadExecutor()
+        );
+    }
+
+    private int pullWifiBytesTransfer(int atomTag, List<StatsEvent> pulledData) {
+        INetworkStatsService networkStatsService = getINetworkStatsService();
+        if (networkStatsService == null) {
+            Slog.e(TAG, "NetworkStats Service is not available!");
+            return StatsManager.PULL_SKIP;
+        }
+        long token = Binder.clearCallingIdentity();
+        try {
+            // TODO: Consider caching the following call to get BatteryStatsInternal.
+            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+            String[] ifaces = bs.getWifiIfaces();
+            if (ifaces.length == 0) {
+                return StatsManager.PULL_SKIP;
+            }
+            // Combine all the metrics per Uid into one record.
+            NetworkStats stats = networkStatsService.getDetailedUidStats(ifaces).groupedByUid();
+            addNetworkStats(atomTag, pulledData, stats, false);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
+    private void addNetworkStats(
+            int tag, List<StatsEvent> ret, NetworkStats stats, boolean withFGBG) {
+        int size = stats.size();
+        NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
+        for (int j = 0; j < size; j++) {
+            stats.getValues(j, entry);
+            StatsEvent.Builder e = StatsEvent.newBuilder();
+            e.setAtomId(tag);
+            e.writeInt(entry.uid);
+            if (withFGBG) {
+                e.writeInt(entry.set);
+            }
+            e.writeLong(entry.rxBytes);
+            e.writeLong(entry.rxPackets);
+            e.writeLong(entry.txBytes);
+            e.writeLong(entry.txPackets);
+            ret.add(e.build());
+        }
+    }
+
+    private void registerWifiBytesTransferBackground() {
+        // No op.
+    }
+
+    private void pullWifiBytesTransferBackground() {
+        // No op.
+    }
+
+    private void registerMobileBytesTransfer() {
+        // No op.
+    }
+
+    private void pullMobileBytesTransfer() {
+        // No op.
+    }
+
+    private void registerMobileBytesTransferBackground() {
+        // No op.
+    }
+
+    private void pullMobileBytesTransferBackground() {
+        // No op.
+    }
+
+    private void registerBluetoothBytesTransfer() {
+        // No op.
+    }
+
+    private void pullBluetoothBytesTransfer() {
+        // No op.
+    }
+
+    private void registerKernelWakelock() {
+        // No op.
+    }
+
+    private void pullKernelWakelock() {
+        // No op.
+    }
+
+    private void registerCpuTimePerFreq() {
+        // No op.
+    }
+
+    private void pullCpuTimePerFreq() {
+        // No op.
+    }
+
+    private void registerCpuTimePerUid() {
+        // No op.
+    }
+
+    private void pullCpuTimePerUid() {
+        // No op.
+    }
+
+    private void registerCpuTimePerUidFreq() {
+        // No op.
+    }
+
+    private void pullCpuTimeperUidFreq() {
+        // No op.
+    }
+
+    private void registerCpuActiveTime() {
+        // No op.
+    }
+
+    private void pullCpuActiveTime() {
+        // No op.
+    }
+
+    private void registerCpuClusterTime() {
+        // No op.
+    }
+
+    private int pullCpuClusterTime() {
+        return 0;
+    }
+
+    private void registerWifiActivityInfo() {
+        // No op.
+    }
+
+    private void pullWifiActivityInfo() {
+        // No op.
+    }
+
+    private void registerModemActivityInfo() {
+        // No op.
+    }
+
+    private void pullModemActivityInfo() {
+        // No op.
+    }
+
+    private void registerBluetoothActivityInfo() {
+        // No op.
+    }
+
+    private void pullBluetoothActivityInfo() {
+        // No op.
+    }
+
+    private void registerSystemElapsedRealtime() {
+        // No op.
+    }
+
+    private void pullSystemElapsedRealtime() {
+        // No op.
+    }
+
+    private void registerSystemUptime() {
+        // No op.
+    }
+
+    private void pullSystemUptime() {
+        // No op.
+    }
+
+    private void registerRemainingBatteryCapacity() {
+        // No op.
+    }
+
+    private void pullRemainingBatteryCapacity() {
+        // No op.
+    }
+
+    private void registerFullBatteryCapacity() {
+        // No op.
+    }
+
+    private void pullFullBatteryCapacity() {
+        // No op.
+    }
+
+    private void registerBatteryVoltage() {
+        // No op.
+    }
+
+    private void pullBatteryVoltage() {
+        // No op.
+    }
+
+    private void registerBatteryLevel() {
+        // No op.
+    }
+
+    private void pullBatteryLevel() {
+        // No op.
+    }
+
+    private void registerBatteryCycleCount() {
+        // No op.
+    }
+
+    private void pullBatteryCycleCount() {
+        // No op.
+    }
+
+    private void registerProcessMemoryState() {
+        // No op.
+    }
+
+    private void pullProcessMemoryState() {
+        // No op.
+    }
+
+    private void registerProcessMemoryHighWaterMark() {
+        // No op.
+    }
+
+    private void pullProcessMemoryHighWaterMark() {
+        // No op.
+    }
+
+    private void registerProcessMemorySnapshot() {
+        // No op.
+    }
+
+    private void pullProcessMemorySnapshot() {
+        // No op.
+    }
+
+    private void registerSystemIonHeapSize() {
+        // No op.
+    }
+
+    private void pullSystemIonHeapSize() {
+        // No op.
+    }
+
+    private void registerProcessSystemIonHeapSize() {
+        // No op.
+    }
+
+    private void pullProcessSystemIonHeapSize() {
+        // No op.
+    }
+
+    private void registerTemperature() {
+        // No op.
+    }
+
+    private void pullTemperature() {
+        // No op.
+    }
+
+    private void registerCoolingDevice() {
+        // No op.
+    }
+
+    private void pullCooldownDevice() {
+        // No op.
+    }
+
+    private void registerBinderCalls() {
+        // No op.
+    }
+
+    private void pullBinderCalls() {
+        // No op.
+    }
+
+    private void registerBinderCallsExceptions() {
+        // No op.
+    }
+
+    private void pullBinderCallsExceptions() {
+        // No op.
+    }
+
+    private void registerLooperStats() {
+        // No op.
+    }
+
+    private void pullLooperStats() {
+        // No op.
+    }
+
+    private void registerDiskStats() {
+        // No op.
+    }
+
+    private void pullDiskStats() {
+        // No op.
+    }
+
+    private void registerDirectoryUsage() {
+        // No op.
+    }
+
+    private void pullDirectoryUsage() {
+        // No op.
+    }
+
+    private void registerAppSize() {
+        // No op.
+    }
+
+    private void pullAppSize() {
+        // No op.
+    }
+
+    private void registerCategorySize() {
+        // No op.
+    }
+
+    private void pullCategorySize() {
+        // No op.
+    }
+
+    private void registerNumFingerprintsEnrolled() {
+        // No op.
+    }
+
+    private void pullNumFingerprintsEnrolled() {
+        // No op.
+    }
+
+    private void registerNumFacesEnrolled() {
+        // No op.
+    }
+
+    private void pullNumFacesEnrolled() {
+        // No op.
+    }
+
+    private void registerProcStats() {
+        // No op.
+    }
+
+    private void pullProcStats() {
+        // No op.
+    }
+
+    private void registerProcStatsPkgProc() {
+        // No op.
+    }
+
+    private void pullProcStatsPkgProc() {
+        // No op.
+    }
+
+    private void registerDiskIO() {
+        // No op.
+    }
+
+    private void pullDiskIO() {
+        // No op.
+    }
+
+    private void registerPowerProfile() {
+        // No op.
+    }
+
+    private void pullPowerProfile() {
+        // No op.
+    }
+
+    private void registerProcessCpuTime() {
+        // No op.
+    }
+
+    private void pullProcessCpuTime() {
+        // No op.
+    }
+
+    private void registerCpuTimePerThreadFreq() {
+        // No op.
+    }
+
+    private void pullCpuTimePerThreadFreq() {
+        // No op.
+    }
+
+    private void registerDeviceCalculatedPowerUse() {
+        // No op.
+    }
+
+    private void pullDeviceCalculatedPowerUse() {
+        // No op.
+    }
+
+    private void registerDeviceCalculatedPowerBlameUid() {
+        // No op.
+    }
+
+    private void pullDeviceCalculatedPowerBlameUid() {
+        // No op.
+    }
+
+    private void registerDeviceCalculatedPowerBlameOther() {
+        // No op.
+    }
+
+    private void pullDeviceCalculatedPowerBlameOther() {
+        // No op.
+    }
+
+    private void registerDebugElapsedClock() {
+        // No op.
+    }
+
+    private void pullDebugElapsedClock() {
+        // No op.
+    }
+
+    private void registerDebugFailingElapsedClock() {
+        // No op.
+    }
+
+    private void pullDebugFailingElapsedClock() {
+        // No op.
+    }
+
+    private void registerBuildInformation() {
+        // No op.
+    }
+
+    private void pullBuildInformation() {
+        // No op.
+    }
+
+    private void registerRoleHolder() {
+        // No op.
+    }
+
+    private void pullRoleHolder() {
+        // No op.
+    }
+
+    private void registerDangerousPermissionState() {
+        // No op.
+    }
+
+    private void pullDangerousPermissionState() {
+        // No op.
+    }
+
+    private void registerTimeZoneDataInfo() {
+        // No op.
+    }
+
+    private void pullTimeZoneDataInfo() {
+        // No op.
+    }
+
+    private void registerExternalStorageInfo() {
+        // No op.
+    }
+
+    private void pullExternalStorageInfo() {
+        // No op.
+    }
+
+    private void registerAppsOnExternalStorageInfo() {
+        // No op.
+    }
+
+    private void pullAppsOnExternalStorageInfo() {
+        // No op.
+    }
+
+    private void registerFaceSettings() {
+        // No op.
+    }
+
+    private void pullRegisterFaceSettings() {
+        // No op.
+    }
+
+    private void registerAppOps() {
+        // No op.
+    }
+
+    private void pullAppOps() {
+        // No op.
+    }
+
+    private void registerNotificationRemoteViews() {
+        // No op.
+    }
+
+    private void pullNotificationRemoteViews() {
+        // No op.
+    }
+
+    private void registerDangerousPermissionStateSampled() {
+        // No op.
+    }
+
+    private void pullDangerousPermissionStateSampled() {
+        // No op.
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c959439..9fd3ea4 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -163,6 +163,7 @@
 import android.view.DisplayInfo;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.ITaskOrganizer;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -803,6 +804,16 @@
         setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                 false /* creating */);
+
+        windowingMode = getWindowingMode();
+        /*
+         * Different windowing modes may be managed by different task organizers. If
+         * getTaskOrganizer returns null, we still call transferToTaskOrganizer to
+         * make sure we clear it.
+         */
+        final ITaskOrganizer org =
+            mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
+        transferToTaskOrganizer(org);
     }
 
     /**
@@ -1650,6 +1661,33 @@
     }
 
     /**
+     * Indicate whether the first task in this stack is controlled by a TaskOrganizer. We aren't
+     * expecting to use the TaskOrganizer in multiple task per stack scenarios so checking
+     * the first one is ok.
+     */
+    boolean isControlledByTaskOrganizer() {
+        return getChildCount() > 0 && getTopMostTask().mTaskOrganizer != null;
+    }
+
+    private static void transferSingleTaskToOrganizer(Task tr, ITaskOrganizer organizer) {
+        tr.setTaskOrganizer(organizer);
+    }
+
+    /**
+     * Transfer control of the leashes and IWindowContainers to the given ITaskOrganizer.
+     * This will (or shortly there-after) invoke the taskAppeared callbacks.
+     * If the tasks had a previous TaskOrganizer, setTaskOrganizer will take care of
+     * emitting the taskVanished callbacks.
+     */
+    void transferToTaskOrganizer(ITaskOrganizer organizer) {
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                ActivityStack::transferSingleTaskToOrganizer,
+                PooledLambda.__(Task.class), organizer);
+        forAllTasks(c);
+        c.recycle();
+    }
+
+    /**
      * Returns true if the stack should be visible.
      *
      * @param starting The currently starting activity or null if there is none.
@@ -3577,6 +3615,15 @@
     void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, int animationDuration,
             boolean fromFullscreen) {
         if (!inPinnedWindowingMode()) return;
+
+        /**
+         * TODO(b/146594635): Remove all PIP animation code from WM once SysUI handles animation.
+         * If this PIP Task is controlled by a TaskOrganizer, the animation occurs entirely
+         * on the TaskOrganizer side, so we just hand over the leash without doing any animation.
+         * We have to be careful to not schedule the enter-pip callback as the TaskOrganizer
+         * needs to have flexibility to schedule that at an appropriate point in the animation.
+         */
+        if (isControlledByTaskOrganizer()) return;
         if (toBounds == null /* toFullscreen */) {
             final Configuration parentConfig = getParent().getConfiguration();
             final ActivityRecord top = topRunningNonOverlayTaskActivity();
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index d63165a..aa90248 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2548,6 +2548,7 @@
         final PooledConsumer c = PooledLambda.obtainConsumer(
                 ActivityRecord::updatePictureInPictureMode,
                 PooledLambda.__(ActivityRecord.class), targetStackBounds, forceUpdate);
+        task.getStack().setBounds(targetStackBounds);
         task.forAllActivities(c);
         c.recycle();
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 474c5c9..ded603c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -226,6 +226,7 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationRunner;
+import android.view.ITaskOrganizer;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.WindowContainerTransaction;
@@ -662,6 +663,12 @@
 
     private FontScaleSettingObserver mFontScaleSettingObserver;
 
+    /**
+     * Stores the registration and state of TaskOrganizers in use.
+     */
+    TaskOrganizerController mTaskOrganizerController =
+        new TaskOrganizerController(this, mGlobalLock);
+
     private int mDeviceOwnerUid = Process.INVALID_UID;
 
     private final class FontScaleSettingObserver extends ContentObserver {
@@ -1271,6 +1278,14 @@
                 .execute();
     }
 
+    @Override
+    public final void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
+        enforceCallerIsRecentsOrHasPermission(
+                MANAGE_ACTIVITY_STACKS, "registerTaskOrganizer()");
+        synchronized (mGlobalLock) {
+            mTaskOrganizerController.registerTaskOrganizer(organizer, windowingMode);
+        }
+    }
 
     @Override
     public IBinder requestStartActivityPermissionToken(IBinder delegatorToken) {
@@ -3319,6 +3334,18 @@
         }
     }
 
+    private void applyWindowContainerChange(ConfigurationContainer cc,
+            WindowContainerTransaction.Change c) {
+        sanitizeAndApplyConfigChange(cc, c);
+
+        Rect enterPipBounds = c.getEnterPipBounds();
+        if (enterPipBounds != null) {
+            Task tr = (Task) cc;
+            mStackSupervisor.updatePictureInPictureMode(tr,
+                    enterPipBounds, true);
+        }
+    }
+
     @Override
     public void applyContainerTransaction(WindowContainerTransaction t) {
         mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()");
@@ -3335,7 +3362,7 @@
                             entries.next();
                     final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder(
                             entry.getKey()).getContainer();
-                    sanitizeAndApplyConfigChange(cc, entry.getValue());
+                    applyWindowContainerChange(cc, entry.getValue());
                 }
             }
         } finally {
@@ -4057,7 +4084,11 @@
                     throw new IllegalArgumentException("Stack: " + stack
                             + " doesn't support animated resize.");
                 }
-                if (animate) {
+                /**
+                 * TODO(b/146594635): Remove all PIP animation code from WM
+                 * once SysUI handles animation. Don't even try to animate TaskOrganized tasks.
+                 */
+                if (animate && !stack.isControlledByTaskOrganizer()) {
                     stack.animateResizePinnedStack(null /* destBounds */,
                             null /* sourceHintBounds */, animationDuration,
                             false /* fromFullscreen */);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index dd3365c..d0310f1 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -666,4 +666,8 @@
             return sb.toString();
         }
     }
+
+    RemoteToken getRemoteToken() {
+        return mRemoteToken;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index c4b67d7..091f66c 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -279,6 +279,19 @@
         // we avoid reintroducing this concept by just choosing one of them here.
         inputWindowHandle.surfaceInset = child.getAttrs().surfaceInsets.left;
 
+        /**
+         * If the window is in a TaskManaged by a TaskOrganizer then most cropping
+         * will be applied using the SurfaceControl hierarchy from the Organizer.
+         * This means we need to make sure that these changes in crop are reflected
+         * in the input windows, and so ensure this flag is set so that
+         * the input crop always reflects the surface hierarchy.
+         * we may have some issues with modal-windows, but I guess we can
+         * cross that bridge when we come to implementing full-screen TaskOrg
+         */
+        if (child.getTask() != null && child.getTask().isControlledByTaskOrganizer()) {
+            inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
+        }
+
         if (child.mGlobalScale != 1) {
             // If we are scaling the window, input coordinates need
             // to be inversely scaled to map from what is on screen
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a7bf660..c3e815d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2168,12 +2168,18 @@
             mService.continueWindowLayout();
         }
 
+        // TODO(b/146594635): Remove all PIP animation code from WM once SysUI handles animation.
         // Notify the pinned stack controller to prepare the PiP animation, expect callback
-        // delivered from SystemUI to WM to start the animation.
-        final PinnedStackController pinnedStackController =
+        // delivered from SystemUI to WM to start the animation. Unless we are using
+        // the TaskOrganizer in which case the animation will be entirely handled
+        // on that side.
+        if (mService.mTaskOrganizerController.getTaskOrganizer(WINDOWING_MODE_PINNED)
+                == null) {
+            final PinnedStackController pinnedStackController =
                 display.mDisplayContent.getPinnedStackController();
-        pinnedStackController.prepareAnimation(sourceHintBounds, aspectRatio,
-                null /* stackBounds */);
+            pinnedStackController.prepareAnimation(sourceHintBounds, aspectRatio,
+                    null /* stackBounds */);
+        }
 
         // TODO: revisit the following statement after the animation is moved from WM to SysUI.
         // Update the visibility of all activities after the they have been reparented to the new
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index eaa0ea7..399c5d3 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,12 +16,8 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.AnimationSpecProto.ROTATE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS;
-import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA;
-import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA;
 import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
 import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -29,9 +25,7 @@
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
 
-import android.animation.ArgbEvaluator;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -46,9 +40,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
-import com.android.internal.R;
 import com.android.server.protolog.common.ProtoLog;
-import com.android.server.wm.utils.RotationAnimationUtils;
 
 import java.io.PrintWriter;
 
@@ -68,10 +60,10 @@
  *      animation first rotate the new content into the old orientation to then be able to
  *      animate to the new orientation
  *
- * <li> The Background color frame: <p>
- *      To have the animation seem more seamless, we add a color transitioning background behind the
- *      exiting and entering layouts. We compute the brightness of the start and end
- *      layouts and transition from the two brightness values as grayscale underneath the animation
+ * <li> The exiting Blackframe: <p>
+ *     Because the change of orientation might change the width and height of the content (i.e
+ *     when rotating from portrait to landscape) we "crop" the new content using black frames
+ *     around the screenshot so the new content does not go beyond the screenshot's bounds
  *
  * <li> The entering Blackframe: <p>
  *     The enter Blackframe is similar to the exit Blackframe but is only used when a custom
@@ -89,6 +81,8 @@
      */
     private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
     private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
+    private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
+    private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
 
     private final Context mContext;
     private final DisplayContent mDisplayContent;
@@ -96,18 +90,16 @@
     private final Transformation mRotateExitTransformation = new Transformation();
     private final Transformation mRotateEnterTransformation = new Transformation();
     // Complete transformations being applied.
+    private final Transformation mExitTransformation = new Transformation();
     private final Transformation mEnterTransformation = new Transformation();
+    private final Matrix mFrameInitialMatrix = new Matrix();
     private final Matrix mSnapshotInitialMatrix = new Matrix();
+    private final Matrix mSnapshotFinalMatrix = new Matrix();
+    private final Matrix mExitFrameFinalMatrix = new Matrix();
     private final WindowManagerService mService;
-    /** Only used for custom animations and not screen rotation. */
     private SurfaceControl mEnterBlackFrameLayer;
-    /** This layer contains the actual screenshot that is to be faded out. */
-    private SurfaceControl mScreenshotLayer;
-    /**
-     * Only used for screen rotation and not custom animations. Layered behind all other layers
-     * to avoid showing any "empty" spots
-     */
-    private SurfaceControl mBackColorSurface;
+    private SurfaceControl mRotationLayer;
+    private SurfaceControl mSurfaceControl;
     private BlackFrame mEnteringBlackFrame;
     private int mWidth, mHeight;
 
@@ -128,11 +120,8 @@
     private boolean mFinishAnimReady;
     private long mFinishAnimStartTime;
     private boolean mForceDefaultOrientation;
+    private BlackFrame mExitingBlackFrame;
     private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
-    /** Intensity of light/whiteness of the layout before rotation occurs. */
-    private float mStartLuma;
-    /** Intensity of light/whiteness of the layout after rotation occurs. */
-    private float mEndLuma;
 
     public ScreenRotationAnimation(Context context, DisplayContent displayContent,
             boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -173,15 +162,9 @@
 
         final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
         try {
-            mBackColorSurface = displayContent.makeChildSurface(null)
-                    .setName("BackColorSurface")
-                    .setColorLayer()
-                    .build();
-
-            mScreenshotLayer = displayContent.makeOverlay()
+            mRotationLayer = displayContent.makeOverlay()
                     .setName("RotationLayer")
-                    .setBufferSize(mWidth, mHeight)
-                    .setSecure(isSecure)
+                    .setContainerLayer()
                     .build();
 
             mEnterBlackFrameLayer = displayContent.makeOverlay()
@@ -189,21 +172,26 @@
                     .setContainerLayer()
                     .build();
 
+            mSurfaceControl = mService.makeSurfaceBuilder(null)
+                    .setName("ScreenshotSurface")
+                    .setParent(mRotationLayer)
+                    .setBufferSize(mWidth, mHeight)
+                    .setSecure(isSecure)
+                    .build();
+
             // In case display bounds change, screenshot buffer and surface may mismatch so set a
             // scaling mode.
             SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
-            t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+            t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
             t2.apply(true /* sync */);
 
             // Capture a screenshot into the surface we just created.
             final int displayId = display.getDisplayId();
             final Surface surface = mService.mSurfaceFactory.get();
-            surface.copyFrom(mScreenshotLayer);
+            surface.copyFrom(mSurfaceControl);
             SurfaceControl.ScreenshotGraphicBuffer gb =
                     mService.mDisplayManagerInternal.screenshot(displayId);
             if (gb != null) {
-                mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(),
-                        gb.getColorSpace());
                 try {
                     surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
                             gb.getColorSpace());
@@ -214,15 +202,13 @@
                 // screenshot surface we display it in also has FLAG_SECURE so that
                 // the user can not screenshot secure layers via the screenshot surface.
                 if (gb.containsSecureLayers()) {
-                    t.setSecure(mScreenshotLayer, true);
+                    t.setSecure(mSurfaceControl, true);
                 }
-                t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
-                t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
-                t.setLayer(mBackColorSurface, -1);
-                t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
-                t.setAlpha(mBackColorSurface, 1);
-                t.show(mScreenshotLayer);
-                t.show(mBackColorSurface);
+                t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
+                t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
+                t.setAlpha(mSurfaceControl, 0);
+                t.show(mRotationLayer);
+                t.show(mSurfaceControl);
             } else {
                 Slog.w(TAG, "Unable to take screenshot of display " + displayId);
             }
@@ -232,11 +218,32 @@
         }
 
         ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
-                    "  FREEZE %s: CREATE", mScreenshotLayer);
+                    "  FREEZE %s: CREATE", mSurfaceControl);
         setRotation(t, originalRotation);
         t.apply();
     }
 
+    private static void createRotationMatrix(int rotation, int width, int height,
+            Matrix outMatrix) {
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                outMatrix.reset();
+                break;
+            case Surface.ROTATION_90:
+                outMatrix.setRotate(90, 0, 0);
+                outMatrix.postTranslate(height, 0);
+                break;
+            case Surface.ROTATION_180:
+                outMatrix.setRotate(180, 0, 0);
+                outMatrix.postTranslate(width, height);
+                break;
+            case Surface.ROTATION_270:
+                outMatrix.setRotate(270, 0, 0);
+                outMatrix.postTranslate(0, width);
+                break;
+        }
+    }
+
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(STARTED, mStarted);
@@ -245,11 +252,11 @@
     }
 
     boolean hasScreenshot() {
-        return mScreenshotLayer != null;
+        return mSurfaceControl != null;
     }
 
     private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
-        if (mScreenshotLayer == null) {
+        if (mRotationLayer == null) {
             return;
         }
         matrix.getValues(mTmpFloats);
@@ -260,19 +267,24 @@
             x -= mCurrentDisplayRect.left;
             y -= mCurrentDisplayRect.top;
         }
-        t.setPosition(mScreenshotLayer, x, y);
-        t.setMatrix(mScreenshotLayer,
+        t.setPosition(mRotationLayer, x, y);
+        t.setMatrix(mRotationLayer,
                 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
 
-        t.setAlpha(mScreenshotLayer, (float) 1.0);
-        t.show(mScreenshotLayer);
+        t.setAlpha(mSurfaceControl, (float) 1.0);
+        t.setAlpha(mRotationLayer, (float) 1.0);
+        t.show(mRotationLayer);
     }
 
     public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mSurface="); pw.print(mScreenshotLayer);
+        pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
         pw.print(" mWidth="); pw.print(mWidth);
         pw.print(" mHeight="); pw.println(mHeight);
+        pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
+        if (mExitingBlackFrame != null) {
+            mExitingBlackFrame.printTo(prefix + "  ", pw);
+        }
         pw.print(prefix);
         pw.print("mEnteringBlackFrame=");
         pw.println(mEnteringBlackFrame);
@@ -291,10 +303,20 @@
         pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
         pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mExitTransformation=");
+        mExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mEnterTransformation=");
         mEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFrameInitialMatrix=");
+        mFrameInitialMatrix.printShortString(pw);
+        pw.println();
         pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
-        mSnapshotInitialMatrix.printShortString(pw);pw.println();
+        mSnapshotInitialMatrix.printShortString(pw);
+        pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
+        pw.println();
+        pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
+        mExitFrameFinalMatrix.printShortString(pw);
+        pw.println();
         pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
         if (mForceDefaultOrientation) {
             pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
@@ -309,7 +331,7 @@
         // to the snapshot to make it stay in the same original position
         // with the current screen rotation.
         int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
-        RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
+        createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
         setRotationTransform(t, mSnapshotInitialMatrix);
     }
@@ -319,7 +341,7 @@
      */
     private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
-        if (mScreenshotLayer == null) {
+        if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
         }
@@ -332,58 +354,89 @@
         // Figure out how the screen has moved from the original rotation.
         int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
 
+        mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
+                com.android.internal.R.anim.screen_rotate_alpha);
 
         final boolean customAnim;
         if (exitAnim != 0 && enterAnim != 0) {
             customAnim = true;
             mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
             mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
-            mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
-                    R.anim.screen_rotate_alpha);
         } else {
             customAnim = false;
-            switch (delta) { /* Counter-Clockwise Rotations */
+            switch (delta) {
                 case Surface.ROTATION_0:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_0_exit);
+                            com.android.internal.R.anim.screen_rotate_0_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_0_enter);
+                            com.android.internal.R.anim.screen_rotate_0_enter);
                     break;
                 case Surface.ROTATION_90:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_plus_90_exit);
+                            com.android.internal.R.anim.screen_rotate_plus_90_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_plus_90_enter);
+                            com.android.internal.R.anim.screen_rotate_plus_90_enter);
                     break;
                 case Surface.ROTATION_180:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_180_exit);
+                            com.android.internal.R.anim.screen_rotate_180_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_180_enter);
+                            com.android.internal.R.anim.screen_rotate_180_enter);
                     break;
                 case Surface.ROTATION_270:
                     mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_minus_90_exit);
+                            com.android.internal.R.anim.screen_rotate_minus_90_exit);
                     mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
-                            R.anim.screen_rotate_minus_90_enter);
+                            com.android.internal.R.anim.screen_rotate_minus_90_enter);
                     break;
             }
         }
 
-        mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
-        mRotateExitAnimation.restrictDuration(maxAnimationDuration);
-        mRotateExitAnimation.scaleCurrentDuration(animationScale);
+        // Initialize the animations.  This is a hack, redefining what "parent"
+        // means to allow supplying the last and next size.  In this definition
+        // "%p" is the original (let's call it "previous") size, and "%" is the
+        // screen's current/new size.
         mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
-        mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
-        mRotateEnterAnimation.scaleCurrentDuration(animationScale);
-
+        mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mAnimRunning = false;
         mFinishAnimReady = false;
         mFinishAnimStartTime = -1;
 
-        if (customAnim) {
-            mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
-            mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
+        mRotateExitAnimation.restrictDuration(maxAnimationDuration);
+        mRotateExitAnimation.scaleCurrentDuration(animationScale);
+        mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
+        mRotateEnterAnimation.scaleCurrentDuration(animationScale);
+        mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
+        mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
+
+        if (!customAnim && mExitingBlackFrame == null) {
+            try {
+                // Compute the transformation matrix that must be applied
+                // the the black frame to make it stay in the initial position
+                // before the new screen rotation.  This is different than the
+                // snapshot transformation because the snapshot is always based
+                // of the native orientation of the screen, not the orientation
+                // we were last in.
+                createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
+
+                final Rect outer;
+                final Rect inner;
+                if (mForceDefaultOrientation) {
+                    // Going from a smaller Display to a larger Display, add curtains to sides
+                    // or top and bottom. Going from a larger to smaller display will result in
+                    // no BlackSurfaces being constructed.
+                    outer = mCurrentDisplayRect;
+                    inner = mOriginalDisplayRect;
+                } else {
+                    outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
+                    inner = new Rect(0, 0, mWidth, mHeight);
+                }
+                mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
+                        SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
+                        mRotationLayer);
+            } catch (OutOfResourcesException e) {
+                Slog.w(TAG, "Unable to allocate black surface", e);
+            }
         }
 
         if (customAnim && mEnteringBlackFrame == null) {
@@ -398,12 +451,7 @@
             }
         }
 
-        if (customAnim) {
-            mSurfaceRotationAnimationController.startCustomAnimation();
-        } else {
-            mSurfaceRotationAnimationController.startScreenRotationAnimation();
-        }
-
+        mSurfaceRotationAnimationController.startAnimation();
         return true;
     }
 
@@ -412,13 +460,11 @@
      */
     public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
-        if (mScreenshotLayer == null) {
+        if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
         }
         if (!mStarted) {
-            mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),
-                    mDisplayContent.getWindowingLayer());
             startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
                     exitAnim, enterAnim);
         }
@@ -434,28 +480,28 @@
             mSurfaceRotationAnimationController.cancel();
             mSurfaceRotationAnimationController = null;
         }
-
-        if (mScreenshotLayer != null) {
-            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "  FREEZE %s: DESTROY", mScreenshotLayer);
+        if (mSurfaceControl != null) {
+            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "  FREEZE %s: DESTROY", mSurfaceControl);
+            mSurfaceControl = null;
             SurfaceControl.Transaction t = mService.mTransactionFactory.get();
-            if (mScreenshotLayer.isValid()) {
-                t.remove(mScreenshotLayer);
+            if (mRotationLayer != null) {
+                if (mRotationLayer.isValid()) {
+                    t.remove(mRotationLayer);
+                }
+                mRotationLayer = null;
             }
-            mScreenshotLayer = null;
-
             if (mEnterBlackFrameLayer != null) {
                 if (mEnterBlackFrameLayer.isValid()) {
                     t.remove(mEnterBlackFrameLayer);
                 }
                 mEnterBlackFrameLayer = null;
             }
-            if (mBackColorSurface != null) {
-                t.remove(mBackColorSurface);
-                mBackColorSurface = null;
-            }
             t.apply();
         }
-
+        if (mExitingBlackFrame != null) {
+            mExitingBlackFrame.kill();
+            mExitingBlackFrame = null;
+        }
         if (mEnteringBlackFrame != null) {
             mEnteringBlackFrame.kill();
             mEnteringBlackFrame = null;
@@ -491,28 +537,18 @@
      * Utility class that runs a {@link ScreenRotationAnimation} on the {@link
      * SurfaceAnimationRunner}.
      * <p>
-     * The rotation animation supports both screen rotation and custom animations
-     *
-     * For custom animations:
+     * The rotation animation is divided into the following hierarchy:
      * <ul>
-     *   <li>
-     *     The screenshot layer which has an added animation of it's alpha channel
-     *     ("screen_rotate_alpha") and that will be applied along with the custom animation.
-     *   </li>
-     *   <li> A device layer that is animated with the provided custom animation </li>
-     * </ul>
-     *
-     * For screen rotation:
-     * <ul>
-     *   <li> A rotation layer that is both rotated and faded out during a single animation </li>
-     *   <li> A device layer that is both rotated and faded in during a single animation </li>
-     *   <li> A background color layer that transitions colors behind the first two layers </li>
-     * </ul>
-     *
+     * <li> A first rotation layer, containing the blackframes. This layer is animated by the
+     * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
+     *     <ul>
+     *         <li> A child layer containing the screenshot on which is added an animation of it's
+     *     alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
+     *     </ul>
+     * <li> A second rotation layer used when custom animations are passed in
      * {@link ScreenRotationAnimation#startAnimation(
      *     SurfaceControl.Transaction, long, float, int, int, int, int)}.
      * </ul>
-     *
      * <p>
      * Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
      * this three {@link SurfaceControl}s which then delegates the animation to the
@@ -520,35 +556,22 @@
      */
     class SurfaceRotationAnimationController {
         private SurfaceAnimator mDisplayAnimator;
+        private SurfaceAnimator mEnterBlackFrameAnimator;
         private SurfaceAnimator mScreenshotRotationAnimator;
         private SurfaceAnimator mRotateScreenAnimator;
-        private SurfaceAnimator mEnterBlackFrameAnimator;
-
-        void startCustomAnimation() {
-            try {
-                mService.mSurfaceAnimationRunner.deferStartingAnimations();
-                mRotateScreenAnimator = startScreenshotAlphaAnimation();
-                mDisplayAnimator = startDisplayRotation();
-                if (mEnteringBlackFrame != null) {
-                    mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
-                }
-            } finally {
-                mService.mSurfaceAnimationRunner.continueStartingAnimations();
-            }
-        }
 
         /**
          * Start the rotation animation of the display and the screenshot on the
          * {@link SurfaceAnimationRunner}.
          */
-        void startScreenRotationAnimation() {
-            try {
-                mService.mSurfaceAnimationRunner.deferStartingAnimations();
-                mDisplayAnimator = startDisplayRotation();
+        void startAnimation() {
+            mRotateScreenAnimator = startScreenshotAlphaAnimation();
+            mDisplayAnimator = startDisplayRotation();
+            if (mExitingBlackFrame != null) {
                 mScreenshotRotationAnimator = startScreenshotRotationAnimation();
-                startColorAnimation();
-            } finally {
-                mService.mSurfaceAnimationRunner.continueStartingAnimations();
+            }
+            if (mEnteringBlackFrame != null) {
+                mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
             }
         }
 
@@ -573,8 +596,8 @@
 
         private SurfaceAnimator startScreenshotAlphaAnimation() {
             return startAnimation(initializeBuilder()
-                            .setSurfaceControl(mScreenshotLayer)
-                            .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
+                            .setSurfaceControl(mSurfaceControl)
+                            .setAnimationLeashParent(mRotationLayer)
                             .setWidth(mWidth)
                             .setHeight(mHeight)
                             .build(),
@@ -593,67 +616,13 @@
 
         private SurfaceAnimator startScreenshotRotationAnimation() {
             return startAnimation(initializeBuilder()
-                            .setSurfaceControl(mScreenshotLayer)
+                            .setSurfaceControl(mRotationLayer)
                             .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
                             .build(),
                     createWindowAnimationSpec(mRotateExitAnimation),
                     this::onAnimationEnd);
         }
 
-
-        /**
-         * Applies the color change from {@link #mStartLuma} to {@link #mEndLuma} as a
-         * grayscale color
-         */
-        private void startColorAnimation() {
-            int colorTransitionMs = mContext.getResources().getInteger(
-                    R.integer.config_screen_rotation_color_transition);
-            final SurfaceAnimationRunner runner = mService.mSurfaceAnimationRunner;
-            final float[] rgbTmpFloat = new float[3];
-            final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
-            final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
-            final long duration = colorTransitionMs * (long) mService.getCurrentAnimatorScale();
-            final ArgbEvaluator va = ArgbEvaluator.getInstance();
-            runner.startAnimation(
-                new LocalAnimationAdapter.AnimationSpec() {
-                    @Override
-                    public long getDuration() {
-                        return duration;
-                    }
-
-                    @Override
-                    public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
-                        long currentPlayTime) {
-                        float fraction = (float)currentPlayTime / (float)getDuration();
-                        int color = (Integer) va.evaluate(fraction, startColor, endColor);
-                        Color middleColor = Color.valueOf(color);
-                        rgbTmpFloat[0] = middleColor.red();
-                        rgbTmpFloat[1] = middleColor.green();
-                        rgbTmpFloat[2] = middleColor.blue();
-                        if (leash.isValid()) {
-                            t.setColor(leash, rgbTmpFloat);
-                        }
-                    }
-
-                    @Override
-                    public void dump(PrintWriter pw, String prefix) {
-                        pw.println(prefix + "startLuma=" + mStartLuma
-                                + " endLuma=" + mEndLuma
-                                + " durationMs=" + colorTransitionMs);
-                    }
-
-                    @Override
-                    public void dumpDebugInner(ProtoOutputStream proto) {
-                        final long token = proto.start(ROTATE);
-                        proto.write(START_LUMA, mStartLuma);
-                        proto.write(END_LUMA, mEndLuma);
-                        proto.write(DURATION_MS, colorTransitionMs);
-                        proto.end(token);
-                    }
-                },
-                mBackColorSurface, mDisplayContent.getPendingTransaction(), null);
-        }
-
         private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
             return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
                     false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
@@ -677,6 +646,7 @@
 
             LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
                     animationSpec, mService.mSurfaceAnimationRunner);
+
             animator.startAnimation(mDisplayContent.getPendingTransaction(),
                     localAnimationAdapter, false);
             return animator;
@@ -722,6 +692,7 @@
             if (mEnterBlackFrameAnimator != null) {
                 mEnterBlackFrameAnimator.cancelAnimation();
             }
+
             if (mScreenshotRotationAnimator != null) {
                 mScreenshotRotationAnimator.cancelAnimation();
             }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 5633b6b..50cea2e 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -78,10 +78,6 @@
     @GuardedBy("mLock")
     private boolean mAnimationStartDeferred;
 
-    /**
-     * There should only ever be one instance of this class. Usual spot for it is with
-     * {@link WindowManagerService}
-     */
     SurfaceAnimationRunner(Supplier<Transaction> transactionFactory,
             PowerManagerInternal powerManagerInternal) {
         this(null /* callbackProvider */, null /* animatorFactory */,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9a140da..5cb7091 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -117,9 +117,11 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.IBinder;
+import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -130,6 +132,7 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
+import android.view.ITaskOrganizer;
 import android.view.RemoteAnimationTarget;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -425,6 +428,14 @@
     }
 
     /**
+     * The TaskOrganizer which is delegated presentation of this task. If set the Task will
+     * emit an IWindowContainer (allowing access to it's SurfaceControl leash) to the organizers
+     * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
+     */
+    ITaskOrganizer mTaskOrganizer;
+
+
+    /**
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
      */
@@ -445,6 +456,22 @@
                 _voiceSession, _voiceInteractor, stack);
     }
 
+    class TaskToken extends RemoteToken {
+        TaskToken(ConfigurationContainer container) {
+            super(container);
+        }
+
+        @Override
+        public SurfaceControl getLeash() {
+            // We need to copy the SurfaceControl instead of returning the original
+            // because the Parcel FLAGS PARCELABLE_WRITE_RETURN_VALUE cause SurfaceControls
+            // to release themselves.
+            SurfaceControl sc = new SurfaceControl();
+            sc.copyFrom(getSurfaceControl());
+            return sc;
+        }
+    }
+
     /** Don't use constructor directly. This is only used by XML parser. */
     Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
@@ -469,7 +496,7 @@
         mTaskDescription = _lastTaskDescription;
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
         setOrientation(SCREEN_ORIENTATION_UNSET);
-        mRemoteToken = new RemoteToken(this);
+        mRemoteToken = new TaskToken(this);
         affinityIntent = _affinityIntent;
         affinity = _affinity;
         rootAffinity = _rootAffinity;
@@ -2179,6 +2206,10 @@
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
+
+        // If applicable let the TaskOrganizer know the Task is vanishing.
+        setTaskOrganizer(null);
+
         super.removeImmediately();
     }
 
@@ -2567,6 +2598,12 @@
     }
 
     boolean shouldAnimate() {
+        /**
+         * Animations are handled by the TaskOrganizer implementation.
+         */
+        if (isControlledByTaskOrganizer()) {
+            return false;
+        }
         // Don't animate while the task runs recents animation but only if we are in the mode
         // where we cancel with deferred screenshot, which means that the controller has
         // transformed the task.
@@ -3444,4 +3481,91 @@
             XmlUtils.skipCurrentTag(in);
         }
     }
+
+    boolean isControlledByTaskOrganizer() {
+        return mTaskOrganizer != null;
+    }
+
+    @Override
+    protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
+        /**
+         * Avoid yanking back control from the TaskOrganizer, which has presumably reparented the
+         * Surface in to its own hierarchy.
+         */
+        if (isControlledByTaskOrganizer()) {
+            return;
+        }
+        super.reparentSurfaceControl(t, newParent);
+    }
+
+    private void sendTaskAppeared() {
+        if (mSurfaceControl != null && mTaskOrganizer != null) {
+            mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this);
+        }
+    }
+
+    private void sendTaskVanished() {
+        if (mTaskOrganizer != null) {
+            mAtmService.mTaskOrganizerController.onTaskVanished(mTaskOrganizer, this);
+        }
+   }
+
+    void setTaskOrganizer(ITaskOrganizer organizer) {
+        // Let the old organizer know it has lost control.
+        if (mTaskOrganizer != null) {
+            sendTaskVanished();
+        }
+        mTaskOrganizer = organizer;
+        sendTaskAppeared();
+    }
+
+    // Called on Binder death.
+    void taskOrganizerDied() {
+        mTaskOrganizer = null;
+    }
+
+    @Override
+    void setSurfaceControl(SurfaceControl sc) {
+        super.setSurfaceControl(sc);
+        // If the TaskOrganizer was set before we created the SurfaceControl, we need to
+        // emit the callbacks now.
+        sendTaskAppeared();
+    }
+
+    @Override
+    public void updateSurfacePosition() {
+        // Avoid fighting with the TaskOrganizer over Surface position.
+        if (isControlledByTaskOrganizer()) {
+            getPendingTransaction().setPosition(mSurfaceControl, 0, 0);
+            scheduleAnimation();
+            return;
+        } else {
+            super.updateSurfacePosition();
+        }
+    }
+
+    @Override
+    void getRelativeDisplayedPosition(Point outPos) {
+        // In addition to updateSurfacePosition, we keep other code that sets
+        // position from fighting with the TaskOrganizer
+        if (isControlledByTaskOrganizer()) {
+            outPos.set(0, 0);
+            return;
+        }
+        super.getRelativeDisplayedPosition(outPos);
+    }
+
+    @Override
+    public void setWindowingMode(int windowingMode) {
+        super.setWindowingMode(windowingMode);
+        windowingMode = getWindowingMode();
+        /*
+         * Different windowing modes may be managed by different task organizers. If
+         * getTaskOrganizer returns null, we still call transferToTaskOrganizer to
+         * make sure we clear it.
+         */
+        final ITaskOrganizer org =
+            mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
+        setTaskOrganizer(org);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
new file mode 100644
index 0000000..283be40
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -0,0 +1,167 @@
+/*
+ * 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_PINNED;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.ITaskOrganizer;
+import android.view.SurfaceControl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Stores the TaskOrganizers associated with a given windowing mode and
+ * their associated state.
+ */
+class TaskOrganizerController {
+    private static final String TAG = "TaskOrganizerController";
+
+    private WindowManagerGlobalLock mGlobalLock;
+
+    private class DeathRecipient implements IBinder.DeathRecipient {
+        int mWindowingMode;
+        ITaskOrganizer mTaskOrganizer;
+
+        DeathRecipient(ITaskOrganizer organizer, int windowingMode) {
+            mTaskOrganizer = organizer;
+            mWindowingMode = windowingMode;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mGlobalLock) {
+                final TaskOrganizerState state = mTaskOrganizerStates.get(mTaskOrganizer);
+                for (int i = 0; i < state.mOrganizedTasks.size(); i++) {
+                    state.mOrganizedTasks.get(i).taskOrganizerDied();
+                }
+                mTaskOrganizerStates.remove(mTaskOrganizer);
+                if (mTaskOrganizersForWindowingMode.get(mWindowingMode) == mTaskOrganizer) {
+                    mTaskOrganizersForWindowingMode.remove(mWindowingMode);
+                }
+            }
+        }
+    };
+
+    class TaskOrganizerState {
+        ITaskOrganizer mOrganizer;
+        DeathRecipient mDeathRecipient;
+
+        ArrayList<Task> mOrganizedTasks = new ArrayList<>();
+
+        void addTask(Task t) {
+            mOrganizedTasks.add(t);
+        }
+
+        void removeTask(Task t) {
+            mOrganizedTasks.remove(t);
+        }
+
+        TaskOrganizerState(ITaskOrganizer organizer, DeathRecipient deathRecipient) {
+            mOrganizer = organizer;
+            mDeathRecipient = deathRecipient;
+        }
+    };
+
+
+    final HashMap<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
+    final HashMap<ITaskOrganizer, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
+
+    final HashMap<Integer, ITaskOrganizer> mTaskOrganizersByPendingSyncId = new HashMap();
+
+    final ActivityTaskManagerService mService;
+
+    TaskOrganizerController(ActivityTaskManagerService atm, WindowManagerGlobalLock lock) {
+        mService = atm;
+        mGlobalLock = lock;
+    }
+
+    private void clearIfNeeded(int windowingMode) {
+        final TaskOrganizerState oldState = mTaskOrganizersForWindowingMode.get(windowingMode);
+        if (oldState != null) {
+            oldState.mOrganizer.asBinder().unlinkToDeath(oldState.mDeathRecipient, 0);
+        }
+    }
+
+    /**
+     * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
+     * If there was already a TaskOrganizer for this windowing mode it will be evicted
+     * and receive taskVanished callbacks in the process.
+     */
+    void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
+        if (windowingMode != WINDOWING_MODE_PINNED) {
+            throw new UnsupportedOperationException(
+                    "As of now only Pinned windowing mode is supported for registerTaskOrganizer");
+
+        }
+        clearIfNeeded(windowingMode);
+        DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
+        try {
+            organizer.asBinder().linkToDeath(dr, 0);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "TaskOrganizer failed to register death recipient");
+        }
+
+        final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
+        mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+        mTaskOrganizerStates.put(organizer, state);
+    }
+
+    ITaskOrganizer getTaskOrganizer(int windowingMode) {
+        final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode);
+        if (state == null) {
+            return null;
+        }
+        return state.mOrganizer;
+    }
+
+    private void sendTaskAppeared(ITaskOrganizer organizer, Task task) {
+        try {
+            organizer.taskAppeared(task.getRemoteToken(), task.getTaskInfo());
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception sending taskAppeared callback" + e);
+        }
+    }
+
+    private void sendTaskVanished(ITaskOrganizer organizer, Task task) {
+        try {
+            organizer.taskVanished(task.getRemoteToken());
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception sending taskVanished callback" + e);
+        }
+    }
+
+    void onTaskAppeared(ITaskOrganizer organizer, Task task) {
+        TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
+
+        state.addTask(task);
+        sendTaskAppeared(organizer, task);
+    }
+
+    void onTaskVanished(ITaskOrganizer organizer, Task task) {
+        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
+        sendTaskVanished(organizer, task);
+
+        // This could trigger TaskAppeared for other tasks in the same stack so make sure
+        // we do this AFTER sending taskVanished.
+        state.removeTask(task);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8ac212f..f3880fa 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -342,7 +342,7 @@
         if (mSurfaceControl == null) {
             // If we don't yet have a surface, but we now have a parent, we should
             // build a surface.
-            mSurfaceControl = makeSurface().build();
+            setSurfaceControl(makeSurface().build());
             getPendingTransaction().show(mSurfaceControl);
             updateSurfacePosition();
         } else {
@@ -496,7 +496,7 @@
                 mParent.getPendingTransaction().merge(getPendingTransaction());
             }
 
-            mSurfaceControl = null;
+            setSurfaceControl(null);
             mLastSurfacePosition.set(0, 0);
             scheduleAnimation();
         }
@@ -2209,4 +2209,8 @@
         }
         return mParent.getDimmer();
     }
+
+    void setSurfaceControl(SurfaceControl sc) {
+        mSurfaceControl = sc;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
deleted file mode 100644
index 94f6676..0000000
--- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.utils;
-
-import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.view.Display;
-import android.view.Surface;
-import android.view.SurfaceControl;
-
-
-/** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
-public class RotationAnimationUtils {
-
-    /**
-     * Converts the provided {@link GraphicBuffer} and converts it to a bitmap to then sample the
-     * luminance at the borders of the bitmap
-     * @return the average luminance of all the pixels at the borders of the bitmap
-     */
-    public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
-        Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
-        if (hwBitmap == null) {
-            return 0;
-        }
-
-        Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
-        float totalLuma = 0;
-        int height = swaBitmap.getHeight();
-        int width = swaBitmap.getWidth();
-        int i;
-        for (i = 0; i < width; i++) {
-            totalLuma += swaBitmap.getColor(i, 0).luminance();
-            totalLuma += swaBitmap.getColor(i, height - 1).luminance();
-        }
-        for (i = 0; i < height; i++) {
-            totalLuma += swaBitmap.getColor(0, i).luminance();
-            totalLuma += swaBitmap.getColor(width - 1, i).luminance();
-        }
-        return totalLuma / (2 * width + 2 * height);
-    }
-
-    /**
-     * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
-     * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace)
-     */
-    public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
-        if (surfaceControl ==  null) {
-            return 0;
-        }
-
-        Point size = new Point();
-        display.getSize(size);
-        Rect crop = new Rect(0, 0, size.x, size.y);
-        SurfaceControl.ScreenshotGraphicBuffer buffer =
-                SurfaceControl.captureLayers(surfaceControl, crop, 1);
-        return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(),
-                buffer.getColorSpace());
-    }
-
-    public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
-        switch (rotation) {
-            case Surface.ROTATION_0:
-                outMatrix.reset();
-                break;
-            case Surface.ROTATION_90:
-                outMatrix.setRotate(90, 0, 0);
-                outMatrix.postTranslate(height, 0);
-                break;
-            case Surface.ROTATION_180:
-                outMatrix.setRotate(180, 0, 0);
-                outMatrix.postTranslate(width, height);
-                break;
-            case Surface.ROTATION_270:
-                outMatrix.setRotate(270, 0, 0);
-                outMatrix.postTranslate(0, width);
-                break;
-        }
-    }
-}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 6504e31..acb6bea 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -129,7 +129,6 @@
 using android::hardware::hidl_string;
 using android::hardware::hidl_death_recipient;
 
-using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
 using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
@@ -149,6 +148,8 @@
 
 using android::hidl::base::V1_0::IBase;
 
+using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
 using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
 using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
@@ -161,6 +162,7 @@
 using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
 using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_V2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
 using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
 using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
@@ -221,6 +223,7 @@
 sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
 sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
 sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr;
+sp<IGnssConfiguration_V2_1> gnssConfigurationIface_V2_1 = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
 sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
 sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
@@ -1888,7 +1891,17 @@
         gnssNiIface = gnssNi;
     }
 
-    if (gnssHal_V2_0 != nullptr) {
+    if (gnssHal_V2_1 != nullptr) {
+        auto gnssConfiguration = gnssHal_V2_1->getExtensionGnssConfiguration_2_1();
+        if (!gnssConfiguration.isOk()) {
+            ALOGD("Unable to get a handle to GnssConfiguration_V2_1");
+        } else {
+            gnssConfigurationIface_V2_1 = gnssConfiguration;
+            gnssConfigurationIface_V2_0 = gnssConfigurationIface_V2_1;
+            gnssConfigurationIface_V1_1 = gnssConfigurationIface_V2_1;
+            gnssConfigurationIface = gnssConfigurationIface_V2_1;
+        }
+    } else if (gnssHal_V2_0 != nullptr) {
         auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
         if (!gnssConfiguration.isOk()) {
             ALOGD("Unable to get a handle to GnssConfiguration_V2_0");
@@ -1962,7 +1975,11 @@
 static jobject android_location_GnssConfiguration_get_gnss_configuration_version(
         JNIEnv* env, jclass /* jclazz */) {
     jint major, minor;
-    if (gnssConfigurationIface_V2_0 != nullptr) {
+    if (gnssConfigurationIface_V2_1 != nullptr) {
+        major = 2;
+        minor = 1;
+    }
+    else if (gnssConfigurationIface_V2_0 != nullptr) {
         major = 2;
         minor = 0;
     } else if (gnssConfigurationIface_V1_1 != nullptr) {
@@ -2768,7 +2785,7 @@
 
         SingleSatCorrection singleSatCorrection = {
             .singleSatCorrectionFlags = corrFlags,
-            .constellation = static_cast<GnssConstellationType>(constType),
+            .constellation = static_cast<GnssConstellationType_V1_0>(constType),
             .svid = static_cast<uint16_t>(satId),
             .carrierFrequencyHz = carrierFreqHz,
             .probSatIsLos = probSatIsLos,
@@ -2863,8 +2880,8 @@
 static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
                                                                jobject,
                                                                jint suplEs) {
-    if (gnssConfigurationIface_V2_0 != nullptr) {
-        ALOGI("Config parameter SUPL_ES is deprecated in IGnssConfiguration.hal version 2.0.");
+    if (gnssConfigurationIface_V2_0 != nullptr || gnssConfigurationIface_V2_1 != nullptr) {
+        ALOGI("Config parameter SUPL_ES is deprecated in IGnssConfiguration.hal version 2.0 and higher.");
         return JNI_FALSE;
     }
 
@@ -2892,7 +2909,7 @@
 static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
                                                                 jobject,
                                                                 jint gpsLock) {
-    if (gnssConfigurationIface_V2_0 != nullptr) {
+    if (gnssConfigurationIface_V2_0 != nullptr || gnssConfigurationIface_V2_1 != nullptr) {
         ALOGI("Config parameter GPS_LOCK is deprecated in IGnssConfiguration.hal version 2.0.");
         return JNI_FALSE;
     }
@@ -2932,7 +2949,7 @@
 
 static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
         JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
-    if (gnssConfigurationIface_V1_1 == nullptr) {
+    if (gnssConfigurationIface_V1_1 == nullptr && gnssConfigurationIface_V2_1 == nullptr) {
         ALOGI("IGnssConfiguration interface does not support satellite blacklist.");
         return JNI_FALSE;
     }
@@ -2955,11 +2972,24 @@
         return JNI_FALSE;
     }
 
+    if (gnssConfigurationIface_V2_1 != nullptr) {
+        hidl_vec<IGnssConfiguration_V2_1::BlacklistedSource> sources;
+        sources.resize(length);
+
+        for (int i = 0; i < length; i++) {
+            sources[i].constellation = static_cast<GnssConstellationType_V2_0>(constellation_array[i]);
+            sources[i].svid = sv_id_array[i];
+        }
+
+        auto result = gnssConfigurationIface_V2_1->setBlacklist_2_1(sources);
+        return checkHidlReturn(result, "IGnssConfiguration_V2_1 setBlacklist_2_1() failed.");
+    }
+
     hidl_vec<IGnssConfiguration_V1_1::BlacklistedSource> sources;
     sources.resize(length);
 
     for (int i = 0; i < length; i++) {
-        sources[i].constellation = static_cast<GnssConstellationType>(constellation_array[i]);
+        sources[i].constellation = static_cast<GnssConstellationType_V1_0>(constellation_array[i]);
         sources[i].svid = sv_id_array[i];
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java
new file mode 100644
index 0000000..06fb102
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoStoreTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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.location;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UserInfoStoreTest {
+
+    private static final int USER1_ID = 1;
+    private static final int USER1_MANAGED_ID = 11;
+    private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
+    private static final int USER2_ID = 2;
+    private static final int USER2_MANAGED_ID = 12;
+    private static final int[] USER2_PROFILES = new int[]{USER2_ID, USER2_MANAGED_ID};
+
+    @Mock private Context mContext;
+    @Mock private UserManager mUserManager;
+
+    private StaticMockitoSession mMockingSession;
+    private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
+
+    private UserInfoStore mStore;
+
+    @Before
+    public void setUp() {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(ActivityManager.class)
+                .strictness(Strictness.WARN)
+                .startMocking();
+
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+        doAnswer(invocation -> {
+            mBroadcastReceivers.add(invocation.getArgument(0));
+            return null;
+        }).when(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), any(
+                UserHandle.class), any(IntentFilter.class), isNull(), any(Handler.class));
+        doReturn(USER1_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER1_ID);
+        doReturn(USER2_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER2_ID);
+        doReturn(new UserInfo(USER1_ID, "", 0)).when(mUserManager).getProfileParent(
+                USER1_MANAGED_ID);
+        doReturn(new UserInfo(USER2_ID, "", 0)).when(mUserManager).getProfileParent(
+                USER2_MANAGED_ID);
+
+        doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
+
+        mStore = new UserInfoStore(mContext);
+        mStore.onSystemReady();
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockingSession != null) {
+            mMockingSession.finishMocking();
+        }
+    }
+
+    private void switchUser(int userId) {
+        doReturn(userId).when(ActivityManager::getCurrentUser);
+        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE,
+                userId);
+        for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
+            broadcastReceiver.onReceive(mContext, intent);
+        }
+    }
+
+    @Test
+    public void testListeners() {
+        UserInfoStore.UserChangedListener listener = mock(UserInfoStore.UserChangedListener.class);
+        mStore.addListener(listener);
+
+        switchUser(USER1_ID);
+        verify(listener, never()).onUserChanged(anyInt(), anyInt());
+
+        switchUser(USER2_ID);
+        verify(listener).onUserChanged(USER1_ID, USER2_ID);
+
+        switchUser(USER1_ID);
+        verify(listener).onUserChanged(USER2_ID, USER1_ID);
+    }
+
+    @Test
+    public void testCurrentUser() {
+        assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
+
+        switchUser(USER2_ID);
+
+        assertThat(mStore.getCurrentUserId()).isEqualTo(USER2_ID);
+
+        switchUser(USER1_ID);
+
+        assertThat(mStore.getCurrentUserId()).isEqualTo(USER1_ID);
+    }
+
+    @Test
+    public void testIsCurrentUserOrProfile() {
+        assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isTrue();
+        assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isTrue();
+        assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isFalse();
+        assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isFalse();
+
+        switchUser(USER2_ID);
+
+        assertThat(mStore.isCurrentUserOrProfile(USER1_ID)).isFalse();
+        assertThat(mStore.isCurrentUserOrProfile(USER2_ID)).isTrue();
+        assertThat(mStore.isCurrentUserOrProfile(USER1_MANAGED_ID)).isFalse();
+        assertThat(mStore.isCurrentUserOrProfile(USER2_MANAGED_ID)).isTrue();
+    }
+
+    @Test
+    public void testGetParentUserId() {
+        assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
+        assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
+        assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
+        assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
+
+        switchUser(USER2_ID);
+
+        assertThat(mStore.getParentUserId(USER1_ID)).isEqualTo(USER1_ID);
+        assertThat(mStore.getParentUserId(USER2_ID)).isEqualTo(USER2_ID);
+        assertThat(mStore.getParentUserId(USER1_MANAGED_ID)).isEqualTo(USER1_ID);
+        assertThat(mStore.getParentUserId(USER2_MANAGED_ID)).isEqualTo(USER2_ID);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 1829fb7..2fb2021 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -56,7 +57,6 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -182,8 +182,8 @@
     }
 
     private ScanResult createScanResult(String ssid, String bssid) {
-        ScanResult result = new ScanResult();
-        result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
+        ScanResult result = mock(ScanResult.class);
+        result.SSID = ssid;
         result.BSSID = bssid;
         return result;
     }
@@ -794,7 +794,7 @@
     @Test
     public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception {
         List<ScanResult> invalidScanResults = Lists.newArrayList(
-                new ScanResult(),
+                mock(ScanResult.class),
                 createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
                 createScanResult(WifiManager.UNKNOWN_SSID, SCORED_NETWORK.networkKey.wifiKey.bssid),
                 createScanResult(SSID, null),
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 821d97a..670bd81 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -67,13 +67,25 @@
 public class PlatformKeyManagerTest {
 
     private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
-    private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
+    private static final int MIN_GENERATION_ID = 1000000;
+    private static final int PRIMARY_USER_ID_FIXTURE = 0;
     private static final int USER_ID_FIXTURE = 42;
     private static final long USER_SID = 4200L;
     private static final String KEY_ALGORITHM = "AES";
     private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private static final String TESTING_KEYSTORE_KEY_ALIAS = "testing-key-store-key-alias";
 
+    private static final String ENCRYPTION_KEY_ALIAS_1 =
+             "com.android.server.locksettings.recoverablekeystore/platform/42/1000000/encrypt";
+    private static final String DECRYPTION_KEY_ALIAS_1 =
+             "com.android.server.locksettings.recoverablekeystore/platform/42/1000000/decrypt";
+    private static final String DECRYPTION_KEY_FOR_ALIAS_PRIMARY_USER_1 =
+             "com.android.server.locksettings.recoverablekeystore/platform/0/1000000/decrypt";
+    private static final String ENCRYPTION_KEY_ALIAS_2 =
+             "com.android.server.locksettings.recoverablekeystore/platform/42/1000001/encrypt";
+    private static final String DECRYPTION_KEY_ALIAS_2 =
+             "com.android.server.locksettings.recoverablekeystore/platform/42/1000001/decrypt";
+
     @Mock private Context mContext;
     @Mock private KeyStoreProxy mKeyStoreProxy;
     @Mock private KeyguardManager mKeyguardManager;
@@ -114,7 +126,7 @@
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_1),
                 any(),
                 any());
     }
@@ -156,7 +168,7 @@
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any(),
                 any());
     }
@@ -187,19 +199,33 @@
     }
 
     @Test
-    public void init_createsDecryptKeyWithAuthenticationRequired() throws Exception {
-        mPlatformKeyManager.init(USER_ID_FIXTURE);
+    public void init_primaryUser_createsDecryptKeyWithUnlockedDeviceRequired() throws Exception {
+        mPlatformKeyManager.init(PRIMARY_USER_ID_FIXTURE);
 
-        assertTrue(getDecryptKeyProtection().isUserAuthenticationRequired());
+        assertTrue(getDecryptKeyProtectionForPrimaryUser().isUnlockedDeviceRequired());
     }
 
     @Test
-    public void init_createsDecryptKeyWithAuthenticationValidFor15Seconds() throws Exception {
+    public void init_primaryUser_createsDecryptKeyWithoutAuthenticationRequired() throws Exception {
+        mPlatformKeyManager.init(PRIMARY_USER_ID_FIXTURE);
+
+        assertFalse(getDecryptKeyProtectionForPrimaryUser().isUserAuthenticationRequired());
+    }
+
+    @Test
+    public void init_secondaryUser_createsDecryptKeyWithoutUnlockedDeviceRequired()
+            throws Exception {
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
-        assertEquals(
-                USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS,
-                getDecryptKeyProtection().getUserAuthenticationValidityDurationSeconds());
+        assertFalse(getDecryptKeyProtection().isUnlockedDeviceRequired());
+    }
+
+    @Test
+    public void init_secondaryUserUser_createsDecryptKeyWithAuthenticationRequired()
+            throws Exception {
+        mPlatformKeyManager.init(USER_ID_FIXTURE);
+
+        assertTrue(getDecryptKeyProtection().isUserAuthenticationRequired());
     }
 
     @Test
@@ -219,7 +245,7 @@
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy, never()).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any(),
                 any());
     }
@@ -231,7 +257,7 @@
         expectThrows(RemoteException.class, () -> mPlatformKeyManager.init(USER_ID_FIXTURE));
 
         verify(mKeyStoreProxy, never()).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any(),
                 any());
     }
@@ -251,15 +277,15 @@
     public void init_savesGenerationIdToDatabase() throws Exception {
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
-        assertEquals(1,
+        assertEquals(MIN_GENERATION_ID,
                 mRecoverableKeyStoreDb.getPlatformKeyGenerationId(USER_ID_FIXTURE));
     }
 
     @Test
-    public void init_setsGenerationIdTo1() throws Exception {
+    public void init_setsGenerationId() throws Exception {
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
-        assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
+        assertEquals(MIN_GENERATION_ID, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
     }
 
     @Test
@@ -268,22 +294,20 @@
 
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
-        assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
+        assertEquals(MIN_GENERATION_ID + 1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
     }
 
     @Test
     public void init_doesNotIncrementGenerationIdIfKeyAvailable() throws Exception {
         mPlatformKeyManager.init(USER_ID_FIXTURE);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
 
         mPlatformKeyManager.init(USER_ID_FIXTURE);
 
-        assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
+        assertEquals(MIN_GENERATION_ID, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
     }
 
     @Test
@@ -294,226 +318,194 @@
     @Test
     public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy.getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any())).thenReturn(generateAndroidKeyStoreKey());
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any());
     }
 
     @Test
     public void getDecryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(false); // was removed
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true); // new version
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
         when(mKeyStoreProxy.getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any())).thenReturn(generateAndroidKeyStoreKey());
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).containsAlias(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"));
+                eq(DECRYPTION_KEY_ALIAS_1));
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getDecryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(false); // was removed
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(false); // was removed
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).containsAlias(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+                eq(ENCRYPTION_KEY_ALIAS_1));
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
         doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_1),
                 any());
 
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_1),
                 any());
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getDecryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
         doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any());
         when(mKeyStoreProxy.getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any())).thenReturn(generateAndroidKeyStoreKey());
 
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).containsAlias(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"));
+                eq(DECRYPTION_KEY_ALIAS_1));
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getEncryptKey_generatesNewKeyIfDecryptKeyIsUnrecoverable() throws Exception {
         doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
                 any());
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(false); // was removed
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true); // new version
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getEncryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(false); // was removed
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true); // new version
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).containsAlias(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+                eq(ENCRYPTION_KEY_ALIAS_1));
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getEncryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(false); // was removed
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(false); // was removed
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_2)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_2)).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).containsAlias(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+                eq(ENCRYPTION_KEY_ALIAS_1));
         // Attempt to get regenerated key.
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_2),
                 any());
     }
 
     @Test
     public void getEncryptKey_getsEncryptKeyWithCorrectAlias() throws Exception {
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(true);
+                .containsAlias(ENCRYPTION_KEY_ALIAS_1)).thenReturn(true);
         when(mKeyStoreProxy
-                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(true);
+                .containsAlias(DECRYPTION_KEY_ALIAS_1)).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).getKey(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_1),
                 any());
     }
 
@@ -523,7 +515,7 @@
 
         mPlatformKeyManager.regenerate(USER_ID_FIXTURE);
 
-        assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
+        assertEquals(MIN_GENERATION_ID + 1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE));
     }
 
     @Test
@@ -533,17 +525,17 @@
         mPlatformKeyManager.regenerate(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).deleteEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+                eq(ENCRYPTION_KEY_ALIAS_1));
         verify(mKeyStoreProxy).deleteEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"));
+                eq(DECRYPTION_KEY_ALIAS_1));
 
         mPlatformKeyManager.regenerate(USER_ID_FIXTURE);
 
         // Removes second generation keys.
         verify(mKeyStoreProxy).deleteEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"));
+                eq(ENCRYPTION_KEY_ALIAS_2));
         verify(mKeyStoreProxy).deleteEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"));
+                eq(DECRYPTION_KEY_ALIAS_2));
     }
 
     @Test
@@ -553,7 +545,7 @@
         mPlatformKeyManager.regenerate(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_2),
                 any(),
                 any());
     }
@@ -565,14 +557,14 @@
         mPlatformKeyManager.regenerate(USER_ID_FIXTURE);
 
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_2),
                 any(),
                 any());
     }
 
     private KeyProtection getEncryptKeyProtection() throws Exception {
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                eq(ENCRYPTION_KEY_ALIAS_1),
                 any(),
                 mProtectionParameterCaptor.capture());
         return (KeyProtection) mProtectionParameterCaptor.getValue();
@@ -580,7 +572,15 @@
 
     private KeyProtection getDecryptKeyProtection() throws Exception {
         verify(mKeyStoreProxy).setEntry(
-                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                eq(DECRYPTION_KEY_ALIAS_1),
+                any(),
+                mProtectionParameterCaptor.capture());
+        return (KeyProtection) mProtectionParameterCaptor.getValue();
+    }
+
+    private KeyProtection getDecryptKeyProtectionForPrimaryUser() throws Exception {
+        verify(mKeyStoreProxy).setEntry(
+                eq(DECRYPTION_KEY_FOR_ALIAS_PRIMARY_USER_1),
                 any(),
                 mProtectionParameterCaptor.capture());
         return (KeyProtection) mProtectionParameterCaptor.getValue();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 6890017..ac74470 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -29,6 +29,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
@@ -84,7 +85,7 @@
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.Random;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
@@ -157,7 +158,7 @@
     @Mock private PlatformKeyManager mPlatformKeyManager;
     @Mock private ApplicationKeyStorage mApplicationKeyStorage;
     @Mock private CleanupManager mCleanupManager;
-    @Mock private ExecutorService mExecutorService;
+    @Mock private ScheduledExecutorService mExecutorService;
     @Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
 
     private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
@@ -1253,7 +1254,7 @@
         mRecoverableKeyStoreManager.lockScreenSecretAvailable(
                 LockPatternUtils.CREDENTIAL_TYPE_PATTERN, "password".getBytes(), 11);
 
-        verify(mExecutorService).execute(any());
+        verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any());
     }
 
     @Test
@@ -1263,7 +1264,7 @@
                 "password".getBytes(),
                 11);
 
-        verify(mExecutorService).execute(any());
+        verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any());
     }
 
     private static byte[] encryptedApplicationKey(
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index a83d940..f871203 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -98,7 +98,7 @@
             final int[] installedUsers) {
         return new PackageRollbackInfo(
                 new VersionedPackage(packageName, 2), new VersionedPackage(packageName, 1),
-                new IntArray(), new ArrayList<>(), false, IntArray.wrap(installedUsers),
+                new IntArray(), new ArrayList<>(), false, false, IntArray.wrap(installedUsers),
                 new SparseLongArray());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index 757a884..d0d2edc 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -87,13 +87,15 @@
             + "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55},"
             + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':"
             + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'},"
-            + "{'userId':-895,'appId':1,'seInfo':'pingu'}],'isApex':false,'installedUsers':"
+            + "{'userId':-895,'appId':1,'seInfo':'pingu'}],'isApex':false,'isApkInApex':false,"
+            + "'installedUsers':"
             + "[498468432,1111,98464],'ceSnapshotInodes':[{'userId':1,'ceSnapshotInode':-6},"
             + "{'userId':2222,'ceSnapshotInode':81641654445},{'userId':546546,"
             + "'ceSnapshotInode':345689375}]},{'versionRolledBackFrom':{'packageName':'chips',"
             + "'longVersionCode':28},'versionRolledBackTo':{'packageName':'com.chips.test',"
             + "'longVersionCode':48},'pendingBackups':[5],'pendingRestores':[{'userId':18,"
-            + "'appId':-12,'seInfo':''}],'isApex':false,'installedUsers':[55,79],"
+            + "'appId':-12,'seInfo':''}],'isApex':false,'isApkInApex':false,"
+            + "'installedUsers':[55,79],"
             + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
             + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
             + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
@@ -155,7 +157,7 @@
         PackageRollbackInfo pkgInfo1 =
                 new PackageRollbackInfo(new VersionedPackage("com.made.up", 18),
                         new VersionedPackage("com.something.else", 5), new IntArray(),
-                        new ArrayList<>(), false, new IntArray(), new SparseLongArray());
+                        new ArrayList<>(), false, false, new IntArray(), new SparseLongArray());
         pkgInfo1.getPendingBackups().add(8);
         pkgInfo1.getPendingBackups().add(888);
         pkgInfo1.getPendingBackups().add(88885);
@@ -175,7 +177,7 @@
         PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo(
                 new VersionedPackage("another.package", 2),
                 new VersionedPackage("com.test.ing", 48888), new IntArray(), new ArrayList<>(),
-                false, new IntArray(), new SparseLongArray());
+                false, false, new IntArray(), new SparseLongArray());
         pkgInfo2.getPendingBackups().add(57);
 
         pkgInfo2.getPendingRestores().add(
@@ -205,7 +207,7 @@
 
         PackageRollbackInfo pkgInfo1 = new PackageRollbackInfo(new VersionedPackage("blah", 55),
                 new VersionedPackage("blah1", 50), new IntArray(), new ArrayList<>(),
-                false, new IntArray(), new SparseLongArray());
+                false, false, new IntArray(), new SparseLongArray());
         pkgInfo1.getPendingBackups().add(59);
         pkgInfo1.getPendingBackups().add(1245);
         pkgInfo1.getPendingBackups().add(124544);
@@ -224,7 +226,7 @@
 
         PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo(new VersionedPackage("chips", 28),
                 new VersionedPackage("com.chips.test", 48), new IntArray(), new ArrayList<>(),
-                false, new IntArray(), new SparseLongArray());
+                false, false, new IntArray(), new SparseLongArray());
         pkgInfo2.getPendingBackups().add(5);
 
         pkgInfo2.getPendingRestores().add(
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index e368d63..164c883 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -295,7 +295,8 @@
             String packageName, long fromVersion, long toVersion, boolean isApex) {
         return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion),
                 new VersionedPackage(packageName, toVersion),
-                new IntArray(), new ArrayList<>(), isApex, new IntArray(), new SparseLongArray());
+                new IntArray(), new ArrayList<>(), isApex, false, new IntArray(),
+                new SparseLongArray());
     }
 
     private static class PackageRollbackInfoForPackage implements
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ae597e3..62f5230 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3213,9 +3213,11 @@
         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
         mService.mNotificationDelegate.onNotificationVisibilityChanged(
                 new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
+        verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r.sbn), eq(true));
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
         mService.mNotificationDelegate.onNotificationVisibilityChanged(
                 new NotificationVisibility[] {}, new NotificationVisibility[]{nv});
+        verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r.sbn), eq(false));
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
     }
 
@@ -4466,6 +4468,16 @@
     }
 
     @Test
+    public void testOnPanelRevealedAndHidden() {
+        int items = 5;
+        mService.mNotificationDelegate.onPanelRevealed(false, items);
+        verify(mAssistants, times(1)).onPanelRevealed(eq(items));
+
+        mService.mNotificationDelegate.onPanelHidden();
+        verify(mAssistants, times(1)).onPanelHidden();
+    }
+
+    @Test
     public void testOnNotificationSmartReplySent() {
         final int replyIndex = 2;
         final String reply = "Hello";
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
new file mode 100644
index 0000000..8d2da1e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.view.ITaskOrganizer;
+import android.view.SurfaceControl;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskOrganizer}.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:TaskOrganizerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class TaskOrganizerTests extends WindowTestsBase {
+    private ITaskOrganizer makeAndRegisterMockOrganizer() {
+        final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
+        when(organizer.asBinder()).thenReturn(new Binder());
+
+        mWm.mAtmService.registerTaskOrganizer(organizer, WINDOWING_MODE_PINNED);
+
+        return organizer;
+    }
+
+    @Test
+    public void testAppearVanish() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+
+        task.setTaskOrganizer(organizer);
+        verify(organizer).taskAppeared(any(), any());
+        assertTrue(task.isControlledByTaskOrganizer());
+
+        task.removeImmediately();
+        verify(organizer).taskVanished(any());
+    }
+
+    @Test
+    public void testSwapOrganizer() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+        final ITaskOrganizer organizer2 = makeAndRegisterMockOrganizer();
+
+        task.setTaskOrganizer(organizer);
+        verify(organizer).taskAppeared(any(), any());
+        task.setTaskOrganizer(organizer2);
+        verify(organizer).taskVanished(any());
+        verify(organizer2).taskAppeared(any(), any());
+    }
+
+    @Test
+    public void testClearOrganizer() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+
+        task.setTaskOrganizer(organizer);
+        verify(organizer).taskAppeared(any(), any());
+        assertTrue(task.isControlledByTaskOrganizer());
+
+        task.setTaskOrganizer(null);
+        verify(organizer).taskVanished(any());
+        assertFalse(task.isControlledByTaskOrganizer());
+    }
+
+    @Test
+    public void testTransferStackToOrganizer() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final Task task2 = createTaskInStack(stack, 0 /* userId */);
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+
+        stack.transferToTaskOrganizer(organizer);
+
+        verify(organizer, times(2)).taskAppeared(any(), any());
+        assertTrue(task.isControlledByTaskOrganizer());
+        assertTrue(task2.isControlledByTaskOrganizer());
+
+        stack.transferToTaskOrganizer(null);
+
+        verify(organizer, times(2)).taskVanished(any());
+        assertFalse(task.isControlledByTaskOrganizer());
+        assertFalse(task2.isControlledByTaskOrganizer());
+    }
+
+    @Test
+    public void testRegisterTaskOrganizerTaskWindowingModeChanges() throws RemoteException {
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        task.setWindowingMode(WINDOWING_MODE_PINNED);
+        verify(organizer).taskAppeared(any(), any());
+        assertTrue(task.isControlledByTaskOrganizer());
+
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        verify(organizer).taskVanished(any());
+        assertFalse(task.isControlledByTaskOrganizer());
+    }
+
+    @Test
+    public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
+        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final Task task2 = createTaskInStack(stack, 0 /* userId */);
+        stack.setWindowingMode(WINDOWING_MODE_PINNED);
+        verify(organizer, times(2)).taskAppeared(any(), any());
+        assertTrue(task.isControlledByTaskOrganizer());
+        assertTrue(task2.isControlledByTaskOrganizer());
+
+        stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        verify(organizer, times(2)).taskVanished(any());
+        assertFalse(task.isControlledByTaskOrganizer());
+        assertFalse(task2.isControlledByTaskOrganizer());
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
deleted file mode 100644
index 9cda084..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.utils;
-
-import static android.graphics.Bitmap.Config.ARGB_8888;
-
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.GraphicBuffer;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.view.Surface;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class RotationAnimationUtilsTest {
-
-    private static final int BITMAP_HEIGHT = 100;
-    private static final int BITMAP_WIDTH = 100;
-    private static final int POINT_WIDTH = 1000;
-    private static final int POINT_HEIGHT = 2000;
-
-    private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
-    private Matrix mMatrix;
-
-    @Before
-    public void setup() {
-        mMatrix = new Matrix();
-    }
-
-    @Test
-    public void blackLuma() {
-        Bitmap swBitmap = createBitmap(0);
-        GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
-        assertEquals(0, borderLuma, 0);
-    }
-
-    @Test
-    public void whiteLuma() {
-        Bitmap swBitmap = createBitmap(1);
-        GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
-        assertEquals(1, borderLuma, 0);
-    }
-
-    @Test
-    public void whiteImageBlackBorderLuma() {
-        Bitmap swBitmap = createBitmap(1);
-        setBorderLuma(swBitmap, 0);
-        GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
-        assertEquals(0, borderLuma, 0);
-    }
-
-    @Test
-    public void blackImageWhiteBorderLuma() {
-        Bitmap swBitmap = createBitmap(0);
-        setBorderLuma(swBitmap, 1);
-        GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
-        assertEquals(1, borderLuma, 0);
-    }
-
-    @Test
-    public void rotate_0_bottomRight() {
-        RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_0,
-                POINT_WIDTH, POINT_HEIGHT, mMatrix);
-        PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
-        assertEquals(POINT_WIDTH, newPoints.x, 0);
-        assertEquals(POINT_HEIGHT, newPoints.y, 0);
-    }
-
-    @Test
-    public void rotate_90_bottomRight() {
-        RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_90,
-                POINT_WIDTH, POINT_HEIGHT, mMatrix);
-        PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
-        assertEquals(0, newPoints.x, 0);
-        assertEquals(POINT_WIDTH, newPoints.y, 0);
-    }
-
-    @Test
-    public void rotate_180_bottomRight() {
-        RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_180,
-                POINT_WIDTH, POINT_HEIGHT, mMatrix);
-        PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
-        assertEquals(0, newPoints.x, 0);
-        assertEquals(0, newPoints.y, 0);
-    }
-
-    @Test
-    public void rotate_270_bottomRight() {
-        RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_270,
-                POINT_WIDTH, POINT_HEIGHT, mMatrix);
-        PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
-        assertEquals(POINT_HEIGHT, newPoints.x, 0);
-        assertEquals(0, newPoints.y, 0);
-    }
-
-    private PointF checkMappedPoints(int x, int y) {
-        final float[] fs = new float[] {x, y};
-        mMatrix.mapPoints(fs);
-        return new PointF(fs[0], fs[1]);
-    }
-
-    private Bitmap createBitmap(float luma) {
-        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888);
-        for (int i = 0; i < BITMAP_WIDTH; i++) {
-            for (int j = 0; j < BITMAP_HEIGHT; j++) {
-                bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma));
-            }
-        }
-        return bitmap;
-    }
-
-    private GraphicBuffer swBitmapToGraphicsBuffer(Bitmap swBitmap) {
-        Bitmap hwBitmap = swBitmap.copy(Bitmap.Config.HARDWARE, false);
-        return hwBitmap.createGraphicBufferHandle();
-    }
-
-    private void setBorderLuma(Bitmap swBitmap, float luma) {
-        int i;
-        int width = swBitmap.getWidth();
-        int height = swBitmap.getHeight();
-        for (i = 0; i < width; i++) {
-            swBitmap.setPixel(i, 0, Color.argb(1, luma, luma, luma));
-            swBitmap.setPixel(i, height - 1, Color.argb(1, luma, luma, luma));
-        }
-        for (i = 0; i < height; i++) {
-            swBitmap.setPixel(0, i, Color.argb(1, luma, luma, luma));
-            swBitmap.setPixel(width - 1, i, Color.argb(1, luma, luma, luma));
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 8e703fe..3f0aeb5 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -16,16 +16,17 @@
 
 package android.telephony;
 
-import com.android.telephony.Rlog;
-
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.hardware.radio.V1_0.CellInfoType;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.telephony.Rlog;
+
 import java.util.Objects;
 import java.util.UUID;
 
@@ -324,6 +325,86 @@
     }
 
     /** @hide */
+    public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) {
+        if (cellIdentity == null)  return null;
+        switch(cellIdentity.cellInfoType) {
+            case CellInfoType.GSM: {
+                if (cellIdentity.cellIdentityGsm.size() == 1) {
+                    return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
+                }
+                break;
+            }
+            case CellInfoType.WCDMA: {
+                if (cellIdentity.cellIdentityWcdma.size() == 1) {
+                    return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.TD_SCDMA: {
+                if (cellIdentity.cellIdentityTdscdma.size() == 1) {
+                    return new  CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.LTE: {
+                if (cellIdentity.cellIdentityLte.size() == 1) {
+                    return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
+                }
+                break;
+            }
+            case CellInfoType.CDMA: {
+                if (cellIdentity.cellIdentityCdma.size() == 1) {
+                    return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.NONE: break;
+            default: break;
+        }
+        return null;
+    }
+
+    /** @hide */
+    public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) {
+        if (cellIdentity == null)  return null;
+        switch(cellIdentity.cellInfoType) {
+            case CellInfoType.GSM: {
+                if (cellIdentity.cellIdentityGsm.size() == 1) {
+                    return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
+                }
+                break;
+            }
+            case CellInfoType.WCDMA: {
+                if (cellIdentity.cellIdentityWcdma.size() == 1) {
+                    return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.TD_SCDMA: {
+                if (cellIdentity.cellIdentityTdscdma.size() == 1) {
+                    return new  CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.LTE: {
+                if (cellIdentity.cellIdentityLte.size() == 1) {
+                    return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
+                }
+                break;
+            }
+            case CellInfoType.CDMA: {
+                if (cellIdentity.cellIdentityCdma.size() == 1) {
+                    return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
+                }
+                break;
+            }
+            case CellInfoType.NONE: break;
+            default: break;
+        }
+        return null;
+    }
+
+    /** @hide */
     public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) {
         if (ci == null) return null;
         switch (ci.getDiscriminator()) {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index db33be3..eb328a7 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2448,18 +2448,14 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
      * @throws IllegalArgumentException if contentUri is empty
-     * @deprecated use {@link MmsManager#sendMultimediaMessage} instead.
      */
     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
             Bundle configOverrides, PendingIntent sentIntent) {
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
-        if (m != null) {
-            m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides,
-                    sentIntent);
-        }
+        MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri,
+                    locationUrl, configOverrides, sentIntent);
     }
 
     /**
@@ -2483,7 +2479,6 @@
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
-     * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead.
      */
     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
             Bundle configOverrides, PendingIntent downloadedIntent) {
@@ -2493,11 +2488,8 @@
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
-        if (m != null) {
-            m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri,
-                    configOverrides, downloadedIntent);
-        }
+        MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl,
+                contentUri, configOverrides, downloadedIntent);
     }
 
     // MMS send/download failure result codes
@@ -2539,9 +2531,9 @@
      * </p>
      *
      * @return the bundle key/values pairs that contains MMS configuration values
-     *  or an empty bundle if they cannot be found.
      */
-    @NonNull public Bundle getCarrierConfigValues() {
+    @Nullable
+    public Bundle getCarrierConfigValues() {
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
@@ -2550,7 +2542,7 @@
         } catch (RemoteException ex) {
             // ignore it
         }
-        return new Bundle();
+        return null;
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 843c065..405b3a5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -46,6 +46,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
@@ -449,12 +450,8 @@
             case UNKNOWN:
                 modemCount = MODEM_COUNT_SINGLE_MODEM;
                 // check for voice and data support, 0 if not supported
-                if (!isVoiceCapable() && !isSmsCapable() && mContext != null) {
-                    ConnectivityManager cm = (ConnectivityManager) mContext
-                            .getSystemService(Context.CONNECTIVITY_SERVICE);
-                    if (cm != null && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
-                        modemCount = MODEM_COUNT_NO_MODEM;
-                    }
+                if (!isVoiceCapable() && !isSmsCapable() && !isDataCapable()) {
+                    modemCount = MODEM_COUNT_NO_MODEM;
                 }
                 break;
             case DSDS:
@@ -10669,12 +10666,21 @@
     }
 
     /**
+     * Checks whether cellular data connection is enabled in the device.
+     *
+     * Whether cellular data connection is enabled, meaning upon request whether will try to setup
+     * metered data connection considering all factors below:
+     * 1) User turned on data setting {@link #isDataEnabled}.
+     * 2) Carrier allows data to be on.
+     * 3) Network policy.
+     * And possibly others.
+     *
+     * @return {@code true} if the overall data connection is capable; {@code false} if not.
      * @hide
-     * It's similar to isDataEnabled, but unlike isDataEnabled, this API also evaluates
-     * carrierDataEnabled, policyDataEnabled etc to give a final decision of whether mobile data is
-     * capable of using.
      */
-    public boolean isDataCapable() {
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isDataConnectionEnabled() {
         boolean retVal = false;
         try {
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
@@ -10682,13 +10688,24 @@
             if (telephony != null)
                 retVal = telephony.isDataEnabled(subId);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isDataEnabled", e);
+            Log.e(TAG, "Error isDataConnectionEnabled", e);
         } catch (NullPointerException e) {
         }
         return retVal;
     }
 
     /**
+     * Checks if FEATURE_TELEPHONY_DATA is enabled.
+     *
+     * @hide
+     */
+    public boolean isDataCapable() {
+        if (mContext == null) return true;
+        return mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_DATA);
+    }
+
+    /**
      * In this mode, modem will not send specified indications when screen is off.
      * @hide
      */
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 2bc129a..091edd4 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -19,15 +19,17 @@
     static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
     test_suites: ["general-tests"],
     test_config: "RollbackTest.xml",
+    java_resources: [":com.android.apex.apkrollback.test_v2"],
 }
 
 java_test_host {
     name: "StagedRollbackTest",
     srcs: ["StagedRollbackTest/src/**/*.java"],
     libs: ["tradefed"],
-    static_libs: ["testng"],
+    static_libs: ["testng", "compatibility-tradefed"],
     test_suites: ["general-tests"],
     test_config: "StagedRollbackTest.xml",
+    data: [":com.android.apex.apkrollback.test_v1"],
 }
 
 java_test_host {
@@ -37,3 +39,44 @@
     test_suites: ["general-tests"],
     test_config: "MultiUserRollbackTest.xml",
 }
+
+genrule {
+  name: "com.android.apex.apkrollback.test.pem",
+  out: ["com.android.apex.apkrollback.test.pem"],
+  cmd: "openssl genrsa -out $(out) 4096",
+}
+
+genrule {
+  name: "com.android.apex.apkrollback.test.pubkey",
+  srcs: [":com.android.apex.apkrollback.test.pem"],
+  out: ["com.android.apex.apkrollback.test.pubkey"],
+  tools: ["avbtool"],
+  cmd: "$(location avbtool) extract_public_key --key $(in) --output $(out)",
+}
+
+apex_key {
+  name: "com.android.apex.apkrollback.test.key",
+  private_key: ":com.android.apex.apkrollback.test.pem",
+  public_key: ":com.android.apex.apkrollback.test.pubkey",
+  installable: false,
+}
+
+apex {
+  name: "com.android.apex.apkrollback.test_v1",
+  manifest: "testdata/manifest_v1.json",
+  androidManifest: "testdata/AndroidManifest.xml",
+  file_contexts: ":apex.test-file_contexts",
+  key: "com.android.apex.apkrollback.test.key",
+  apps: ["TestAppAv1"],
+  installable: false,
+}
+
+apex {
+  name: "com.android.apex.apkrollback.test_v2",
+  manifest: "testdata/manifest_v2.json",
+  androidManifest: "testdata/AndroidManifest.xml",
+  file_contexts: ":apex.test-file_contexts",
+  key: "com.android.apex.apkrollback.test.key",
+  apps: ["TestAppAv2"],
+  installable: false,
+}
\ No newline at end of file
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 9e490f7..3877cc1 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -435,11 +435,64 @@
         // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
         // committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
         // so there is only one rollback to commit when testing native crashes.
-        RollbackManager rm  = RollbackUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
         rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
                 .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
     }
 
+    private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+    private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1",
+            APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
+    private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
+            APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
+    private static final TestApp TEST_APP_A_V2_UNKNOWN = new TestApp("Av2Unknown", TestApp.A, 0,
+            /*isApex*/false, "TestAppAv2.apk");
+
+    @Test
+    public void testRollbackApexWithApk_Phase1() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+
+        int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
+                .commit();
+        InstallUtils.waitForSessionReady(sessionId);
+    }
+
+    @Test
+    public void testRollbackApexWithApk_Phase2() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.processUserData(TestApp.A);
+
+        RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
+        assertThat(available).isStaged();
+        assertThat(available).packagesContainsExactly(
+                Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
+                Rollback.from(TEST_APP_A_V2_UNKNOWN).to(TestApp.A1));
+
+        RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
+        RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
+        assertThat(committed).isNotNull();
+        assertThat(committed).isStaged();
+        assertThat(committed).packagesContainsExactly(
+                Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
+                Rollback.from(TEST_APP_A_V2_UNKNOWN).to(TestApp.A1));
+        assertThat(committed).causePackagesContainsExactly(TEST_APEX_WITH_APK_V2);
+        assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1);
+
+        // Note: The app is not rolled back until after the rollback is staged
+        // and the device has been rebooted.
+        InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+        assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
+    }
+
+    @Test
+    public void testRollbackApexWithApk_Phase3() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+    }
+
     private static void runShellCommand(String cmd) {
         ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 91577c2..6daa6bc 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.testng.Assert.assertThrows;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
@@ -27,6 +28,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -48,14 +50,32 @@
                     phase));
     }
 
+    private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+
     @Before
     public void setUp() throws Exception {
+        if (!getDevice().isAdbRoot()) {
+            getDevice().enableAdbRoot();
+        }
+        getDevice().remountSystemWritable();
+        getDevice().executeShellCommand(
+                "rm -f /system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex "
+                        + "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
         getDevice().reboot();
     }
 
     @After
     public void tearDown() throws Exception {
         runPhase("testCleanUp");
+
+        if (!getDevice().isAdbRoot()) {
+            getDevice().enableAdbRoot();
+        }
+        getDevice().remountSystemWritable();
+        getDevice().executeShellCommand(
+                "rm -f /system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex "
+                        + "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
+        getDevice().reboot();
     }
 
     /**
@@ -184,6 +204,28 @@
         runPhase("testRollbackDataPolicy_Phase3");
     }
 
+    /**
+     * Tests that userdata of apk-in-apex is restored when apex is rolled back.
+     */
+    @Test
+    public void testRollbackApexWithApk() throws Exception {
+        getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
+        final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
+        final File apex = buildHelper.getTestFile(fileName);
+        if (!getDevice().isAdbRoot()) {
+            getDevice().enableAdbRoot();
+        }
+        getDevice().remountSystemWritable();
+        assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+        getDevice().reboot();
+        runPhase("testRollbackApexWithApk_Phase1");
+        getDevice().reboot();
+        runPhase("testRollbackApexWithApk_Phase2");
+        getDevice().reboot();
+        runPhase("testRollbackApexWithApk_Phase3");
+    }
+
     private void crashProcess(String processName, int numberOfCrashes) throws Exception {
         String pid = "";
         String lastPid = "invalid";
diff --git a/tests/RollbackTest/testdata/AndroidManifest.xml b/tests/RollbackTest/testdata/AndroidManifest.xml
new file mode 100644
index 0000000..f21ec89
--- /dev/null
+++ b/tests/RollbackTest/testdata/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.apex.apkrollback.test">
+    <!-- APEX does not have classes.dex -->
+    <application android:hasCode="false" />
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29"/>
+</manifest>
+
diff --git a/tests/RollbackTest/testdata/manifest_v1.json b/tests/RollbackTest/testdata/manifest_v1.json
new file mode 100644
index 0000000..1762fc6
--- /dev/null
+++ b/tests/RollbackTest/testdata/manifest_v1.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.apex.apkrollback.test",
+  "version": 1
+}
diff --git a/tests/RollbackTest/testdata/manifest_v2.json b/tests/RollbackTest/testdata/manifest_v2.json
new file mode 100644
index 0000000..c5127b9c
--- /dev/null
+++ b/tests/RollbackTest/testdata/manifest_v2.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.apex.apkrollback.test",
+  "version": 2
+}
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
new file mode 100644
index 0000000..8a13dbc
--- /dev/null
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+
+android_test {
+    name: "TaskOrganizerTest",
+    srcs: ["**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
new file mode 100644
index 0000000..0cb6c10
--- /dev/null
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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.test.taskembed">
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <application>
+      <service android:name=".TaskOrganizerPipTest"
+               android:exported="true">
+      </service>
+    </application>
+</manifest>
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
new file mode 100644
index 0000000..6ffa19d
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.taskembed;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.Service;
+import android.app.WindowConfiguration;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+public class TaskOrganizerPipTest extends Service {
+    static final int PIP_WIDTH  = 640;
+    static final int PIP_HEIGHT = 360;
+
+    class PipOrgView extends SurfaceView implements SurfaceHolder.Callback {
+        PipOrgView(Context c) {
+            super(c);
+            getHolder().addCallback(this);
+            setZOrderOnTop(true);
+        }
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            try {
+                ActivityTaskManager.getService().registerTaskOrganizer(mOrganizer,
+                        WindowConfiguration.WINDOWING_MODE_PINNED);
+            } catch (Exception e) {
+            }
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+        }
+
+        void reparentTask(IWindowContainer wc) {
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            SurfaceControl leash = null;
+            try {
+                leash = wc.getLeash();
+            } catch (Exception e) {
+                // System server died.. oh well
+            }
+            t.reparent(leash, getSurfaceControl())
+                .setPosition(leash, 0, 0)
+                .apply();
+        }
+    }
+
+    PipOrgView mPipView;
+
+    class Organizer extends ITaskOrganizer.Stub {
+        public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
+            mPipView.reparentTask(wc);
+
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
+            wct.scheduleFinishEnterPip(wc, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
+            try {
+                ActivityTaskManager.getService().applyContainerTransaction(wct);
+            } catch (Exception e) {
+            }
+        }
+        public void taskVanished(IWindowContainer wc) {
+        }
+        public void transactionReady(int id, SurfaceControl.Transaction t) {
+        }
+    }
+
+    Organizer mOrganizer = new Organizer();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
+        wlp.setTitle("TaskOrganizerPipTest");
+        wlp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        wlp.width = wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+
+        FrameLayout layout = new FrameLayout(this);
+        ViewGroup.LayoutParams lp =
+            new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
+        mPipView = new PipOrgView(this);
+        layout.addView(mPipView, lp);
+
+        WindowManager wm = getSystemService(WindowManager.class);
+        wm.addView(layout, wlp);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 46105f4..0b2077d 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -149,7 +149,12 @@
         The package name of the class containing the field/method.
     """
     full_class_name = signature.split(";->")[0]
-    package_name = full_class_name[1:full_class_name.rindex("/")]
+    # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy
+    if (full_class_name[0] != "L"):
+        raise ValueError("Expected to start with 'L': %s" % full_class_name)
+    full_class_name = full_class_name[1:]
+    # If full_class_name doesn't contain '/', then package_name will be ''.
+    package_name = full_class_name.rpartition("/")[0]
     return package_name.replace('/', '.')
 
 class FlagsDict:
diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp
index 79dce4a..7b2ca9a 100644
--- a/tools/lock_agent/Android.bp
+++ b/tools/lock_agent/Android.bp
@@ -25,6 +25,7 @@
     srcs: ["agent.cpp"],
     static_libs: [
         "libbase",
+        "liblog",
         "libz",
         "slicer",
     ],
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 180368c..286be0b 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -32,6 +32,7 @@
         // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
         // to a separate package.
         "java/android/net/wifi/WifiNetworkScoreCache.java",
+        "java/android/net/wifi/WifiOemConfigStoreMigrationHook.java",
         "java/android/net/wifi/wificond/*.java",
         ":libwificond_ipc_aidl",
     ],
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 9c1475f..c0e0890 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -116,12 +116,12 @@
         /**
          * Whether this network is shared credential with user to allow user manually connect.
          */
-        private boolean mIsUserAllowed;
+        private boolean mIsSharedWithUser;
 
         /**
-         * Whether the setIsUserAllowedToManuallyConnect have been called.
+         * Whether the setCredentialSharedWithUser have been called.
          */
-        private boolean mIsUserAllowedBeenSet;
+        private boolean mIsSharedWithUserSet;
         /**
          * Pre-shared key for use with WAPI-PSK networks.
          */
@@ -146,8 +146,8 @@
             mIsAppInteractionRequired = false;
             mIsUserInteractionRequired = false;
             mIsMetered = false;
-            mIsUserAllowed = true;
-            mIsUserAllowedBeenSet = false;
+            mIsSharedWithUser = true;
+            mIsSharedWithUserSet = false;
             mPriority = UNASSIGNED_PRIORITY;
             mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
             mWapiPskPassphrase = null;
@@ -430,13 +430,13 @@
          * <li>If not set, defaults to true (i.e. allow user to manually connect) for secure
          * networks and false for open networks.</li>
          *
-         * @param isAllowed {@code true} to indicate that the credentials may be used by the user to
+         * @param isShared {@code true} to indicate that the credentials may be used by the user to
          *                              manually connect to the network, {@code false} otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsUserAllowedToManuallyConnect(boolean isAllowed) {
-            mIsUserAllowed = isAllowed;
-            mIsUserAllowedBeenSet = true;
+        public @NonNull Builder setCredentialSharedWithUser(boolean isShared) {
+            mIsSharedWithUser = isShared;
+            mIsSharedWithUserSet = true;
             return this;
         }
 
@@ -602,11 +602,11 @@
                 }
                 wifiConfiguration = buildWifiConfiguration();
                 if (wifiConfiguration.isOpenNetwork()) {
-                    if (mIsUserAllowedBeenSet && mIsUserAllowed) {
+                    if (mIsSharedWithUserSet && mIsSharedWithUser) {
                         throw new IllegalStateException("Open network should not be "
-                                + "setIsUserAllowedToManuallyConnect to true");
+                                + "setCredentialSharedWithUser to true");
                     }
-                    mIsUserAllowed = false;
+                    mIsSharedWithUser = false;
                 }
             }
 
@@ -615,7 +615,7 @@
                     mPasspointConfiguration,
                     mIsAppInteractionRequired,
                     mIsUserInteractionRequired,
-                    mIsUserAllowed);
+                    mIsSharedWithUser);
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java b/wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java
new file mode 100755
index 0000000..642dcb9
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiOemConfigStoreMigrationHook.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 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.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Class used to provide one time hooks for existing OEM devices to migrate their config store
+ * data to the wifi mainline module.
+ * <p>
+ * Note:
+ * <li> OEM's need to implement {@link #load()} only if their
+ * existing config store format or file locations differs from the vanilla AOSP implementation (
+ * which is what the wifi mainline module understands).
+ * </li>
+ * <li> The wifi mainline module will invoke {@link #load()}  method on every bootup, its
+ * the responsibility of the OEM implementation to ensure that this method returns non-null data
+ * only on the first bootup. Once the migration is done, the OEM can safely delete their config
+ * store files and then return null on any subsequent reboots. The first & only relevant invocation
+ * of {@link #load()} occurs when a previously released device upgrades to the wifi
+ * mainline module from an OEM implementation of the wifi stack.
+ * </li>
+ * @hide
+ */
+@SystemApi
+public final class WifiOemConfigStoreMigrationHook {
+    /**
+     * Container for all the wifi config data to migrate.
+     */
+    public static final class MigrationData implements Parcelable {
+        /**
+         * Builder to create instance of {@link MigrationData}.
+         */
+        public static final class Builder {
+            private List<WifiConfiguration> mUserSavedNetworkConfigurations;
+            private SoftApConfiguration mUserSoftApConfiguration;
+
+            public Builder() {
+                mUserSavedNetworkConfigurations = null;
+                mUserSoftApConfiguration = null;
+            }
+
+            /**
+             * Sets the list of all user's saved network configurations parsed from OEM config
+             * store files.
+             *
+             * @param userSavedNetworkConfigurations List of {@link WifiConfiguration} representing
+             *                                       the list of user's saved networks
+             * @return Instance of {@link Builder} to enable chaining of the builder method.
+             */
+            public @NonNull Builder setUserSavedNetworkConfigurations(
+                    @NonNull List<WifiConfiguration> userSavedNetworkConfigurations) {
+                checkNotNull(userSavedNetworkConfigurations);
+                mUserSavedNetworkConfigurations = userSavedNetworkConfigurations;
+                return this;
+            }
+
+            /**
+             * Sets the user's softap configuration parsed from OEM config store files.
+             *
+             * @param userSoftApConfiguration {@link SoftApConfiguration} representing user's
+             *                                SoftAp configuration
+             * @return Instance of {@link Builder} to enable chaining of the builder method.
+             */
+            public @NonNull Builder setUserSoftApConfiguration(
+                    @NonNull SoftApConfiguration userSoftApConfiguration) {
+                checkNotNull(userSoftApConfiguration);
+                mUserSoftApConfiguration  = userSoftApConfiguration;
+                return this;
+            }
+
+            /**
+             * Build an instance of {@link MigrationData}.
+             *
+             * @return Instance of {@link MigrationData}.
+             */
+            public @NonNull MigrationData build() {
+                return new MigrationData(mUserSavedNetworkConfigurations, mUserSoftApConfiguration);
+            }
+        }
+
+        private final List<WifiConfiguration> mUserSavedNetworkConfigurations;
+        private final SoftApConfiguration mUserSoftApConfiguration;
+
+        private MigrationData(
+                @Nullable List<WifiConfiguration> userSavedNetworkConfigurations,
+                @Nullable SoftApConfiguration userSoftApConfiguration) {
+            mUserSavedNetworkConfigurations = userSavedNetworkConfigurations;
+            mUserSoftApConfiguration = userSoftApConfiguration;
+        }
+
+        public static final @NonNull Parcelable.Creator<MigrationData> CREATOR =
+                new Parcelable.Creator<MigrationData>() {
+                    @Override
+                    public MigrationData createFromParcel(Parcel in) {
+                        List<WifiConfiguration> userSavedNetworkConfigurations =
+                                in.readArrayList(null);
+                        SoftApConfiguration userSoftApConfiguration = in.readParcelable(null);
+                        return new MigrationData(
+                                userSavedNetworkConfigurations, userSoftApConfiguration);
+                    }
+
+                    @Override
+                    public MigrationData[] newArray(int size) {
+                        return new MigrationData[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeList(mUserSavedNetworkConfigurations);
+            dest.writeParcelable(mUserSoftApConfiguration, flags);
+        }
+
+        /**
+         * Returns list of all user's saved network configurations.
+         *
+         * Note: Only to be returned if there is any format change in how OEM persisted this info.
+         * @return List of {@link WifiConfiguration} representing the list of user's saved networks,
+         * or null if no migration necessary.
+         */
+        @Nullable
+        public List<WifiConfiguration> getUserSavedNetworkConfigurations() {
+            return mUserSavedNetworkConfigurations;
+        }
+
+        /**
+         * Returns user's softap configuration.
+         *
+         * Note: Only to be returned if there is any format change in how OEM persisted this info.
+         * @return {@link SoftApConfiguration} representing user's SoftAp configuration,
+         * or null if no migration necessary.
+         */
+        @Nullable
+        public SoftApConfiguration getUserSoftApConfiguration() {
+            return mUserSoftApConfiguration;
+        }
+    }
+
+    private WifiOemConfigStoreMigrationHook() { }
+
+    /**
+     * Load data from OEM's config store.
+     *
+     * @return Instance of {@link MigrationData} for migrating data, null if no
+     * migration is necessary.
+     */
+    @Nullable
+    public static MigrationData load() {
+        // Note: OEM's should add code to parse data from their config store format here!
+        return null;
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 4cdc4bc..ac91544 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -76,7 +76,7 @@
                 .setSsid(TEST_SSID)
                 .setWpa2Passphrase(TEST_PRESHARED_KEY)
                 .setIsAppInteractionRequired(true)
-                .setIsUserAllowedToManuallyConnect(false)
+                .setCredentialSharedWithUser(false)
                 .setPriority(0)
                 .build();
 
@@ -151,7 +151,7 @@
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
-                .setIsUserAllowedToManuallyConnect(true)
+                .setCredentialSharedWithUser(true)
                 .build();
 
         assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -709,14 +709,14 @@
 
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
-     * when {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} to
+     * when {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to
      * true on a open network suggestion.
      */
     @Test(expected = IllegalStateException.class)
     public void testSetIsUserAllowedToManuallyConnectToWithOpenNetwork() {
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
-                .setIsUserAllowedToManuallyConnect(true)
+                .setCredentialSharedWithUser(true)
                 .build();
     }
 }