Merge "Creates new java_library target to create lite version of launcher.proto."
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 b01cc61..5ce5d61 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
@@ -39341,6 +39343,7 @@
     field @Deprecated public static final String LONGITUDE = "longitude";
     field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field @Deprecated public static final String PICASA_ID = "picasa_id";
+    field public static final String SCENE_CAPTURE_TYPE = "scene_capture_type";
   }
 
   public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
diff --git a/api/system-current.txt b/api/system-current.txt
index 803b4f0..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
   }
@@ -6183,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);
@@ -10425,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/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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4a8e4e2..a11f41f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -726,7 +726,17 @@
     /** @hide Capture the device's display contents and/or audio */
     @UnsupportedAppUsage
     public static final int OP_PROJECT_MEDIA = 46;
-    /** @hide Activate a VPN connection without user intervention. */
+    /**
+     * Start (without additional user intervention) a VPN connection, as used by {@link
+     * android.net.VpnService} along with as Platform VPN connections, as used by {@link
+     * android.net.VpnManager}
+     *
+     * <p>This appop is granted to apps that have already been given user consent to start
+     * VpnService based VPN connections. As this is a superset of OP_ACTIVATE_PLATFORM_VPN, this
+     * appop also allows the starting of Platform VPNs.
+     *
+     * @hide
+     */
     @UnsupportedAppUsage
     public static final int OP_ACTIVATE_VPN = 47;
     /** @hide Access the WallpaperManagerAPI to write wallpapers. */
@@ -852,10 +862,21 @@
     public static final int OP_MANAGE_EXTERNAL_STORAGE = 92;
     /** @hide Communicate cross-profile within the same profile group. */
     public static final int OP_INTERACT_ACROSS_PROFILES = 93;
+    /**
+     * Start (without additional user intervention) a Platform VPN connection, as used by {@link
+     * android.net.VpnManager}
+     *
+     * <p>This appop is granted to apps that have already been given user consent to start Platform
+     * VPN connections. This appop is insufficient to start VpnService based VPNs; OP_ACTIVATE_VPN
+     * is needed for that.
+     *
+     * @hide
+     */
+    public static final int OP_ACTIVATE_PLATFORM_VPN = 94;
 
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 94;
+    public static final int _NUM_OP = 95;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1149,6 +1170,8 @@
     /** @hide Communicate cross-profile within the same profile group. */
     @SystemApi
     public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
+    /** @hide Start Platform VPN without user intervention */
+    public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
 
 
     /** {@link #sAppOpsToNote} not initialized yet for this op */
@@ -1333,6 +1356,7 @@
             OP_QUERY_ALL_PACKAGES,              // QUERY_ALL_PACKAGES
             OP_MANAGE_EXTERNAL_STORAGE,         // MANAGE_EXTERNAL_STORAGE
             OP_INTERACT_ACROSS_PROFILES,        //INTERACT_ACROSS_PROFILES
+            OP_ACTIVATE_PLATFORM_VPN,           // ACTIVATE_PLATFORM_VPN
     };
 
     /**
@@ -1433,6 +1457,7 @@
             OPSTR_QUERY_ALL_PACKAGES,
             OPSTR_MANAGE_EXTERNAL_STORAGE,
             OPSTR_INTERACT_ACROSS_PROFILES,
+            OPSTR_ACTIVATE_PLATFORM_VPN,
     };
 
     /**
@@ -1533,7 +1558,8 @@
             "ACCESS_MEDIA_LOCATION",
             "QUERY_ALL_PACKAGES",
             "MANAGE_EXTERNAL_STORAGE",
-            "INTERACT_ACROSS_PROFILES"
+            "INTERACT_ACROSS_PROFILES",
+            "ACTIVATE_PLATFORM_VPN",
     };
 
     /**
@@ -1636,6 +1662,7 @@
             null, // no permission for OP_QUERY_ALL_PACKAGES
             Manifest.permission.MANAGE_EXTERNAL_STORAGE,
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+            null, // no permission for OP_ACTIVATE_PLATFORM_VPN
     };
 
     /**
@@ -1738,6 +1765,7 @@
             null, // QUERY_ALL_PACKAGES
             null, // MANAGE_EXTERNAL_STORAGE
             null, // INTERACT_ACROSS_PROFILES
+            null, // ACTIVATE_PLATFORM_VPN
     };
 
     /**
@@ -1839,6 +1867,7 @@
             false, // QUERY_ALL_PACKAGES
             false, // MANAGE_EXTERNAL_STORAGE
             false, // INTERACT_ACROSS_PROFILES
+            false, // ACTIVATE_PLATFORM_VPN
     };
 
     /**
@@ -1939,6 +1968,7 @@
             AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
             AppOpsManager.MODE_DEFAULT, // MANAGE_EXTERNAL_STORAGE
             AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
+            AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
     };
 
     /**
@@ -2043,6 +2073,7 @@
             false, // QUERY_ALL_PACKAGES
             false, // MANAGE_EXTERNAL_STORAGE
             false, // INTERACT_ACROSS_PROFILES
+            false, // ACTIVATE_PLATFORM_VPN
     };
 
     /**
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index d993ec1..3febf71 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -256,10 +256,10 @@
     };
 
     @DataClass.Generated(
-            time = 1578321462996L,
+            time = 1578516519372L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=93L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=94L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
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/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/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/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/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/Dvr.java b/media/java/android/media/tv/tuner/Dvr.java
deleted file mode 100644
index 0bfba8f..0000000
--- a/media/java/android/media/tv/tuner/Dvr.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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.NonNull;
-import android.media.tv.tuner.Tuner.DvrCallback;
-import android.media.tv.tuner.Tuner.Filter;
-import android.os.ParcelFileDescriptor;
-
-/** @hide */
-public class Dvr {
-    private long mNativeContext;
-    private DvrCallback mCallback;
-
-    private native int nativeAttachFilter(Filter filter);
-    private native int nativeDetachFilter(Filter filter);
-    private native int nativeConfigureDvr(DvrSettings settings);
-    private native int nativeStartDvr();
-    private native int nativeStopDvr();
-    private native int nativeFlushDvr();
-    private native int nativeClose();
-    private native void nativeSetFileDescriptor(int fd);
-    private native int nativeRead(int size);
-    private native int nativeRead(byte[] bytes, int offset, int size);
-    private native int nativeWrite(int size);
-    private native int nativeWrite(byte[] bytes, int offset, int size);
-
-    private Dvr() {}
-
-    /**
-     * Attaches a filter to DVR interface for recording.
-     *
-     * @param filter the filter to be attached.
-     * @return result status of the operation.
-     */
-    public int attachFilter(Filter filter) {
-        return nativeAttachFilter(filter);
-    }
-
-    /**
-     * Detaches a filter from DVR interface.
-     *
-     * @param filter the filter to be detached.
-     * @return result status of the operation.
-     */
-    public int detachFilter(Filter filter) {
-        return nativeDetachFilter(filter);
-    }
-
-    /**
-     * Configures the DVR.
-     *
-     * @param settings the settings of the DVR interface.
-     * @return result status of the operation.
-     */
-    public int configure(DvrSettings settings) {
-        return nativeConfigureDvr(settings);
-    }
-
-    /**
-     * Starts DVR.
-     *
-     * Starts consuming playback data or producing data for recording.
-     *
-     * @return result status of the operation.
-     */
-    public int start() {
-        return nativeStartDvr();
-    }
-
-    /**
-     * Stops DVR.
-     *
-     * Stops consuming playback data or producing data for recording.
-     *
-     * @return result status of the operation.
-     */
-    public int stop() {
-        return nativeStopDvr();
-    }
-
-    /**
-     * Flushed DVR data.
-     *
-     * @return result status of the operation.
-     */
-    public int flush() {
-        return nativeFlushDvr();
-    }
-
-    /**
-     * closes the DVR instance to release resources.
-     *
-     * @return result status of the operation.
-     */
-    public int close() {
-        return nativeClose();
-    }
-
-    /**
-     * Sets file descriptor to read/write data.
-     */
-    public void setFileDescriptor(ParcelFileDescriptor fd) {
-        nativeSetFileDescriptor(fd.getFd());
-    }
-
-    /**
-     * Reads data from the file for DVR playback.
-     */
-    public int read(int size) {
-        return nativeRead(size);
-    }
-
-    /**
-     * Reads data from the buffer for DVR playback.
-     */
-    public int read(@NonNull byte[] bytes, int offset, int size) {
-        if (size + offset > bytes.length) {
-            throw new ArrayIndexOutOfBoundsException(
-                    "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size);
-        }
-        return nativeRead(bytes, offset, size);
-    }
-
-    /**
-     * Writes recording data to file.
-     */
-    public int write(int size) {
-        return nativeWrite(size);
-    }
-
-    /**
-     * Writes recording data to buffer.
-     */
-    public int write(@NonNull byte[] bytes, int offset, int size) {
-        return nativeWrite(bytes, offset, size);
-    }
-}
diff --git a/media/java/android/media/tv/tuner/DvrSettings.java b/media/java/android/media/tv/tuner/DvrSettings.java
deleted file mode 100644
index 76160dc..0000000
--- a/media/java/android/media/tv/tuner/DvrSettings.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.media.tv.tuner.TunerConstants.DataFormat;
-import android.media.tv.tuner.TunerConstants.DvrSettingsType;
-
-/**
- * DVR settings.
- *
- * @hide
- */
-public class DvrSettings {
-    private int mStatusMask;
-    private int mLowThreshold;
-    private int mHighThreshold;
-    private int mPacketSize;
-
-    @DataFormat
-    private int mDataFormat;
-    @DvrSettingsType
-    private int mType;
-
-    private DvrSettings(int statusMask, int lowThreshold, int highThreshold, int packetSize,
-            @DataFormat int dataFormat, @DvrSettingsType int type) {
-        mStatusMask = statusMask;
-        mLowThreshold = lowThreshold;
-        mHighThreshold = highThreshold;
-        mPacketSize = packetSize;
-        mDataFormat = dataFormat;
-        mType = type;
-    }
-
-    /**
-     * Creates a new builder.
-     */
-    public static Builder newBuilder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for DvrSettings.
-     */
-    public static final class Builder {
-        private int mStatusMask;
-        private int mLowThreshold;
-        private int mHighThreshold;
-        private int mPacketSize;
-        @DataFormat
-        private int mDataFormat;
-        @DvrSettingsType
-        private int mType;
-
-        /**
-         * Sets status mask.
-         */
-        public Builder setStatusMask(int statusMask) {
-            this.mStatusMask = statusMask;
-            return this;
-        }
-
-        /**
-         * Sets low threshold.
-         */
-        public Builder setLowThreshold(int lowThreshold) {
-            this.mLowThreshold = lowThreshold;
-            return this;
-        }
-
-        /**
-         * Sets high threshold.
-         */
-        public Builder setHighThreshold(int highThreshold) {
-            this.mHighThreshold = highThreshold;
-            return this;
-        }
-
-        /**
-         * Sets packet size.
-         */
-        public Builder setPacketSize(int packetSize) {
-            this.mPacketSize = packetSize;
-            return this;
-        }
-
-        /**
-         * Sets data format.
-         */
-        public Builder setDataFormat(@DataFormat int dataFormat) {
-            this.mDataFormat = dataFormat;
-            return this;
-        }
-
-        /**
-         * Sets settings type.
-         */
-        public Builder setType(@DvrSettingsType int type) {
-            this.mType = type;
-            return this;
-        }
-
-        /**
-         * Builds a DvrSettings instance.
-         */
-        public DvrSettings build() {
-            return new DvrSettings(
-                    mStatusMask, mLowThreshold, mHighThreshold, mPacketSize, mDataFormat, mType);
-        }
-    }
-}
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/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index f8b46b3..862489f 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -25,8 +25,10 @@
 import android.media.tv.tuner.TunerConstants.FilterSubtype;
 import android.media.tv.tuner.TunerConstants.FrontendScanType;
 import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.dvr.Dvr;
 import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
 import android.media.tv.tuner.filter.FilterEvent;
+import android.media.tv.tuner.filter.TimeFilter;
 import android.media.tv.tuner.frontend.FrontendCallback;
 import android.media.tv.tuner.frontend.FrontendInfo;
 import android.media.tv.tuner.frontend.FrontendStatus;
@@ -415,8 +417,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();
     }
 
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 203eff8..76c3f23 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)
@@ -80,20 +51,6 @@
 
 
     /** @hide */
-    @IntDef({DATA_FORMAT_TS, DATA_FORMAT_PES, DATA_FORMAT_ES, DATA_FORMAT_SHV_TLV})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DataFormat {}
-    /** @hide */
-    public static final int DATA_FORMAT_TS = Constants.DataFormat.TS;
-    /** @hide */
-    public static final int DATA_FORMAT_PES = Constants.DataFormat.PES;
-    /** @hide */
-    public static final int DATA_FORMAT_ES = Constants.DataFormat.ES;
-    /** @hide */
-    public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV;
-
-
-    /** @hide */
     @IntDef({DEMUX_T_PID, DEMUX_MMPT_PID})
     @Retention(RetentionPolicy.SOURCE)
     public @interface DemuxPidType {}
@@ -102,30 +59,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,
@@ -171,8 +104,8 @@
     public static final int FILTER_SUBTYPE_PTP = 16;
 
     /** @hide */
-    @IntDef({FILTER_STATUS_DATA_READY, FILTER_STATUS_LOW_WATER, FILTER_STATUS_HIGH_WATER,
-            FILTER_STATUS_OVERFLOW})
+    @IntDef(flag = true, prefix = "FILTER_STATUS_", value = {FILTER_STATUS_DATA_READY,
+            FILTER_STATUS_LOW_WATER, FILTER_STATUS_HIGH_WATER, FILTER_STATUS_OVERFLOW})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FilterStatus {}
 
@@ -201,6 +134,187 @@
      */
     public static final int FILTER_STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
 
+    /**
+     * Indexes can be tagged through TS (Transport Stream) header.
+     *
+     * @hide
+     */
+    @IntDef(flag = true, value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+            TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
+            TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
+            TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR, TS_INDEX_PCR_FLAG,
+            TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG, TS_INDEX_PRIVATE_DATA,
+            TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TsIndex {}
+
+    /**
+     * TS index FIRST_PACKET.
+     * @hide
+     */
+    public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+    /**
+     * TS index PAYLOAD_UNIT_START_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
+            Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+    /**
+     * TS index CHANGE_TO_NOT_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
+    /**
+     * TS index CHANGE_TO_EVEN_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
+    /**
+     * TS index CHANGE_TO_ODD_SCRAMBLED.
+     * @hide
+     */
+    public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
+            Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
+    /**
+     * TS index DISCONTINUITY_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
+            Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
+    /**
+     * TS index RANDOM_ACCESS_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
+            Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
+    /**
+     * TS index PRIORITY_INDICATOR.
+     * @hide
+     */
+    public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
+    /**
+     * TS index PCR_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
+    /**
+     * TS index OPCR_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
+    /**
+     * TS index SPLICING_POINT_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_SPLICING_POINT_FLAG =
+            Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
+    /**
+     * TS index PRIVATE_DATA.
+     * @hide
+     */
+    public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
+    /**
+     * TS index ADAPTATION_EXTENSION_FLAG.
+     * @hide
+     */
+    public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
+            Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+
+    /**
+     * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
+     * according to ISO/IEC 13818-1.
+     * @hide
+     */
+    @IntDef(flag = true, value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
+            SC_INDEX_SEQUENCE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScIndex {}
+
+    /**
+     * SC index for a new I-frame.
+     * @hide
+     */
+    public static final int SC_INDEX_I_FRAME = Constants.DemuxScIndex.I_FRAME;
+    /**
+     * SC index for a new P-frame.
+     * @hide
+     */
+    public static final int SC_INDEX_P_FRAME = Constants.DemuxScIndex.P_FRAME;
+    /**
+     * SC index for a new B-frame.
+     * @hide
+     */
+    public static final int SC_INDEX_B_FRAME = Constants.DemuxScIndex.B_FRAME;
+    /**
+     * SC index for a new sequence.
+     * @hide
+     */
+    public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
+
+
+    /**
+     * Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
+     *
+     * @hide
+     */
+    @IntDef(flag = true,
+            value = {SC_HEVC_INDEX_SPS, SC_HEVC_INDEX_AUD, SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+            SC_HEVC_INDEX_SLICE_BLA_W_RADL, SC_HEVC_INDEX_SLICE_BLA_N_LP,
+            SC_HEVC_INDEX_SLICE_IDR_W_RADL, SC_HEVC_INDEX_SLICE_IDR_N_LP,
+            SC_HEVC_INDEX_SLICE_TRAIL_CRA})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScHevcIndex {}
+
+    /**
+     * SC HEVC index SPS.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SPS = Constants.DemuxScHevcIndex.SPS;
+    /**
+     * SC HEVC index AUD.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_AUD = Constants.DemuxScHevcIndex.AUD;
+    /**
+     * SC HEVC index SLICE_CE_BLA_W_LP.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP =
+            Constants.DemuxScHevcIndex.SLICE_CE_BLA_W_LP;
+    /**
+     * SC HEVC index SLICE_BLA_W_RADL.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL =
+            Constants.DemuxScHevcIndex.SLICE_BLA_W_RADL;
+    /**
+     * SC HEVC index SLICE_BLA_N_LP.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP =
+            Constants.DemuxScHevcIndex.SLICE_BLA_N_LP;
+    /**
+     * SC HEVC index SLICE_IDR_W_RADL.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL =
+            Constants.DemuxScHevcIndex.SLICE_IDR_W_RADL;
+    /**
+     * SC HEVC index SLICE_IDR_N_LP.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP =
+            Constants.DemuxScHevcIndex.SLICE_IDR_N_LP;
+    /**
+     * SC HEVC index SLICE_TRAIL_CRA.
+     * @hide
+     */
+    public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA =
+            Constants.DemuxScHevcIndex.SLICE_TRAIL_CRA;
+
+
     /** @hide */
     @IntDef({FRONTEND_SCAN_UNDEFINED, FRONTEND_SCAN_AUTO, FRONTEND_SCAN_BLIND})
     @Retention(RetentionPolicy.SOURCE)
@@ -727,73 +841,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)
@@ -1252,15 +1299,6 @@
     /** @hide */
     public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP;
 
-    /** @hide */
-    @IntDef({DVR_SETTINGS_RECORD, DVR_SETTINGS_PLAYBACK})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DvrSettingsType {}
-    /** @hide */
-    public static final int DVR_SETTINGS_RECORD = Constants.DvrType.RECORD;
-    /** @hide */
-    public static final int DVR_SETTINGS_PLAYBACK = Constants.DvrType.PLAYBACK;
-
 
     /** @hide */
     @IntDef({RESULT_SUCCESS, RESULT_UNAVAILABLE, RESULT_NOT_INITIALIZED, RESULT_INVALID_STATE,
diff --git a/media/java/android/media/tv/tuner/dvr/Dvr.java b/media/java/android/media/tv/tuner/dvr/Dvr.java
new file mode 100644
index 0000000..f90042b
--- /dev/null
+++ b/media/java/android/media/tv/tuner/dvr/Dvr.java
@@ -0,0 +1,186 @@
+/*
+ * 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.dvr;
+
+import android.annotation.BytesLong;
+import android.annotation.NonNull;
+import android.media.tv.tuner.Tuner.DvrCallback;
+import android.media.tv.tuner.Tuner.Filter;
+import android.media.tv.tuner.TunerConstants.Result;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Digital Video Record (DVR) interface provides record control on Demux's output buffer and
+ * playback control on Demux's input buffer.
+ *
+ * @hide
+ */
+public class Dvr {
+    private long mNativeContext;
+    private DvrCallback mCallback;
+
+    private native int nativeAttachFilter(Filter filter);
+    private native int nativeDetachFilter(Filter filter);
+    private native int nativeConfigureDvr(DvrSettings settings);
+    private native int nativeStartDvr();
+    private native int nativeStopDvr();
+    private native int nativeFlushDvr();
+    private native int nativeClose();
+    private native void nativeSetFileDescriptor(int fd);
+    private native int nativeRead(long size);
+    private native int nativeRead(byte[] bytes, long offset, long size);
+    private native int nativeWrite(long size);
+    private native int nativeWrite(byte[] bytes, long offset, long size);
+
+    private Dvr() {}
+
+    /**
+     * Attaches a filter to DVR interface for recording.
+     *
+     * @param filter the filter to be attached.
+     * @return result status of the operation.
+     */
+    @Result
+    public int attachFilter(@NonNull Filter filter) {
+        return nativeAttachFilter(filter);
+    }
+
+    /**
+     * Detaches a filter from DVR interface.
+     *
+     * @param filter the filter to be detached.
+     * @return result status of the operation.
+     */
+    @Result
+    public int detachFilter(@NonNull Filter filter) {
+        return nativeDetachFilter(filter);
+    }
+
+    /**
+     * Configures the DVR.
+     *
+     * @param settings the settings of the DVR interface.
+     * @return result status of the operation.
+     */
+    @Result
+    public int configure(@NonNull DvrSettings settings) {
+        return nativeConfigureDvr(settings);
+    }
+
+    /**
+     * Starts DVR.
+     *
+     * <p>Starts consuming playback data or producing data for recording.
+     *
+     * @return result status of the operation.
+     */
+    @Result
+    public int start() {
+        return nativeStartDvr();
+    }
+
+    /**
+     * Stops DVR.
+     *
+     * <p>Stops consuming playback data or producing data for recording.
+     *
+     * @return result status of the operation.
+     */
+    @Result
+    public int stop() {
+        return nativeStopDvr();
+    }
+
+    /**
+     * Flushed DVR data.
+     *
+     * <p>The data in DVR buffer is cleared.
+     *
+     * @return result status of the operation.
+     */
+    @Result
+    public int flush() {
+        return nativeFlushDvr();
+    }
+
+    /**
+     * Closes the DVR instance to release resources.
+     *
+     * @return result status of the operation.
+     */
+    @Result
+    public int close() {
+        return nativeClose();
+    }
+
+    /**
+     * Sets file descriptor to read/write data.
+     *
+     * @param fd the file descriptor to read/write data.
+     */
+    public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) {
+        nativeSetFileDescriptor(fd.getFd());
+    }
+
+    /**
+     * Reads data from the file for DVR playback.
+     *
+     * @param size the maximum number of bytes to read.
+     * @return the number of bytes read.
+     */
+    public int read(@BytesLong long size) {
+        return nativeRead(size);
+    }
+
+    /**
+     * Reads data from the buffer for DVR playback and copies to the given byte array.
+     *
+     * @param bytes the byte array to store the data.
+     * @param offset the index of the first byte in {@code bytes} to copy to.
+     * @param size the maximum number of bytes to read.
+     * @return the number of bytes read.
+     */
+    public int read(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) {
+        if (size + offset > bytes.length) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size);
+        }
+        return nativeRead(bytes, offset, size);
+    }
+
+    /**
+     * Writes recording data to file.
+     *
+     * @param size the maximum number of bytes to write.
+     * @return the number of bytes written.
+     */
+    public int write(@BytesLong long size) {
+        return nativeWrite(size);
+    }
+
+    /**
+     * Writes recording data to buffer.
+     *
+     * @param bytes the byte array stores the data to be written to DVR.
+     * @param offset the index of the first byte in {@code bytes} to be written to DVR.
+     * @param size the maximum number of bytes to write.
+     * @return the number of bytes written.
+     */
+    public int write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) {
+        return nativeWrite(bytes, offset, size);
+    }
+}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrSettings.java b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
new file mode 100644
index 0000000..46efd7a
--- /dev/null
+++ b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
@@ -0,0 +1,179 @@
+/*
+ * 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.dvr;
+
+import android.annotation.BytesLong;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerConstants.FilterStatus;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * DVR settings used to configure {@link Dvr}.
+ *
+ * @hide
+ */
+public class DvrSettings {
+
+    /** @hide */
+    @IntDef(prefix = "DATA_FORMAT_",
+            value = {DATA_FORMAT_TS, DATA_FORMAT_PES, DATA_FORMAT_ES, DATA_FORMAT_SHV_TLV})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataFormat {}
+
+    /**
+     * Transport Stream.
+     */
+    public static final int DATA_FORMAT_TS = Constants.DataFormat.TS;
+    /**
+     * Packetized Elementary Stream.
+     */
+    public static final int DATA_FORMAT_PES = Constants.DataFormat.PES;
+    /**
+     * Elementary Stream.
+     */
+    public static final int DATA_FORMAT_ES = Constants.DataFormat.ES;
+    /**
+     * TLV (type-length-value) Stream for SHV
+     */
+    public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV;
+
+
+    /** @hide */
+    @IntDef(prefix = "TYPE_", value = {TYPE_RECORD, TYPE_PLAYBACK})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /**
+     * DVR for recording.
+     */
+    public static final int TYPE_RECORD = Constants.DvrType.RECORD;
+    /**
+     * DVR for playback of recorded programs.
+     */
+    public static final int TYPE_PLAYBACK = Constants.DvrType.PLAYBACK;
+
+
+
+    private final int mStatusMask;
+    private final long mLowThreshold;
+    private final long mHighThreshold;
+    private final long mPacketSize;
+
+    @DataFormat
+    private final int mDataFormat;
+    @Type
+    private final int mType;
+
+    private DvrSettings(int statusMask, long lowThreshold, long highThreshold, long packetSize,
+            @DataFormat int dataFormat, @Type int type) {
+        mStatusMask = statusMask;
+        mLowThreshold = lowThreshold;
+        mHighThreshold = highThreshold;
+        mPacketSize = packetSize;
+        mDataFormat = dataFormat;
+        mType = type;
+    }
+
+    /**
+     * Creates a builder for {@link DvrSettings}.
+     */
+    @NonNull
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link DvrSettings}.
+     */
+    public static final class Builder {
+        private int mStatusMask;
+        private long mLowThreshold;
+        private long mHighThreshold;
+        private long mPacketSize;
+        @DataFormat
+        private int mDataFormat;
+        @Type
+        private int mType;
+
+        /**
+         * Sets status mask.
+         */
+        @NonNull
+        public Builder setStatusMask(@FilterStatus int statusMask) {
+            this.mStatusMask = statusMask;
+            return this;
+        }
+
+        /**
+         * Sets low threshold in bytes.
+         */
+        @NonNull
+        public Builder setLowThreshold(@BytesLong long lowThreshold) {
+            this.mLowThreshold = lowThreshold;
+            return this;
+        }
+
+        /**
+         * Sets high threshold in bytes.
+         */
+        @NonNull
+        public Builder setHighThreshold(@BytesLong long highThreshold) {
+            this.mHighThreshold = highThreshold;
+            return this;
+        }
+
+        /**
+         * Sets packet size in bytes.
+         */
+        @NonNull
+        public Builder setPacketSize(@BytesLong long packetSize) {
+            this.mPacketSize = packetSize;
+            return this;
+        }
+
+        /**
+         * Sets data format.
+         */
+        @NonNull
+        public Builder setDataFormat(@DataFormat int dataFormat) {
+            this.mDataFormat = dataFormat;
+            return this;
+        }
+
+        /**
+         * Sets settings type.
+         */
+        @NonNull
+        public Builder setType(@Type int type) {
+            this.mType = type;
+            return this;
+        }
+
+        /**
+         * Builds a {@link DvrSettings} object.
+         */
+        @NonNull
+        public DvrSettings build() {
+            return new DvrSettings(
+                    mStatusMask, mLowThreshold, mHighThreshold, mPacketSize, mDataFormat, mType);
+        }
+    }
+}
diff --git a/media/java/android/media/tv/tuner/filter/AudioDescriptor.java b/media/java/android/media/tv/tuner/filter/AudioDescriptor.java
new file mode 100644
index 0000000..c88c07f
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/AudioDescriptor.java
@@ -0,0 +1,106 @@
+/*
+ * 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.filter;
+
+/**
+ * Meta data from AD (Audio Descriptor) according to ETSI TS 101 154 V2.1.1.
+ *
+ * @hide
+ */
+public class AudioDescriptor {
+    private final byte mAdFade;
+    private final byte mAdPan;
+    private final char mVersionTextTag;
+    private final byte mAdGainCenter;
+    private final byte mAdGainFront;
+    private final byte mAdGainSurround;
+
+    // This constructor is used by JNI code only
+    private AudioDescriptor(byte adFade, byte adPan, char versionTextTag, byte adGainCenter,
+            byte adGainFront, byte adGainSurround) {
+        mAdFade = adFade;
+        mAdPan = adPan;
+        mVersionTextTag = versionTextTag;
+        mAdGainCenter = adGainCenter;
+        mAdGainFront = adGainFront;
+        mAdGainSurround = adGainSurround;
+    }
+
+    /**
+     * Gets AD fade byte.
+     *
+     * <p>Takes values between 0x00 (representing no fade of the main programme sound) and 0xFF
+     * (representing a full fade). Over the range 0x00 to 0xFE one lsb represents a step in
+     * attenuation of the programme sound of 0.3 dB giving a range of 76.2 dB. The fade value of
+     * 0xFF represents no programme sound at all (i.e. mute).
+     */
+    public byte getAdFade() {
+        return mAdFade;
+    }
+
+    /**
+     * Gets AD pan byte.
+     *
+     * <p>Takes values between 0x00 representing a central forward presentation of the audio
+     * description and 0xFF, each increment representing a 360/256 degree step clockwise looking
+     * down on the listener (i.e. just over 1.4 degrees).
+     */
+    public byte getAdPan() {
+        return mAdPan;
+    }
+
+    /**
+     * Gets AD version tag. A single ASCII character version indicates the version.
+     *
+     * <p>A single ASCII character version designator (here "1" indicates revision 1).
+     */
+    public char getVersionTextTag() {
+        return mVersionTextTag;
+    }
+
+    /**
+     * Gets AD gain byte center in dB.
+     *
+     * <p>Represents a signed value in dB. Takes values between 0x7F (representing +76.2 dB boost of
+     * the main programme center) and 0x80 (representing a full fade). Over the range 0x00 to 0x7F
+     * one lsb represents a step in boost of the programme center of 0.6 dB giving a maximum boost
+     * of +76.2 dB. Over the range 0x81 to 0x00 one lsb represents a step in attenuation of the
+     * programme center of 0.6 dB giving a maximum attenuation of -76.2 dB. The gain value of 0x80
+     * represents no main center level at all (i.e. mute).
+     */
+    public byte getAdGainCenter() {
+        return mAdGainCenter;
+    }
+
+    /**
+     * Gets AD gain byte front in dB.
+     *
+     * <p>Same as {@link #getAdGainCenter()}, but applied to left and right front channel.
+     */
+    public byte getAdGainFront() {
+        return mAdGainFront;
+    }
+
+    /**
+     * Gets AD gain byte surround in dB.
+     *
+     * <p>Same as {@link #getAdGainCenter()}, but applied to all surround channels
+     */
+    public byte getAdGainSurround() {
+        return mAdGainSurround;
+    }
+}
diff --git a/media/java/android/media/tv/tuner/filter/AudioExtraMetaData.java b/media/java/android/media/tv/tuner/filter/AudioExtraMetaData.java
deleted file mode 100644
index 306de84..0000000
--- a/media/java/android/media/tv/tuner/filter/AudioExtraMetaData.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.filter;
-
-/**
- * Extra Meta Data from AD (Audio Descriptor) according to
- * ETSI TS 101 154 V2.1.1.
- * @hide
- */
-public class AudioExtraMetaData {
-    private byte mAdFade;
-    private byte mAdPan;
-    private byte mVersionTextTag;
-    private byte mAdGainCenter;
-    private byte mAdGainFront;
-    private byte mAdGainSurround;
-}
diff --git a/media/java/android/media/tv/tuner/filter/DownloadEvent.java b/media/java/android/media/tv/tuner/filter/DownloadEvent.java
index 548fa77..591e4e5 100644
--- a/media/java/android/media/tv/tuner/filter/DownloadEvent.java
+++ b/media/java/android/media/tv/tuner/filter/DownloadEvent.java
@@ -16,15 +16,65 @@
 
 package android.media.tv.tuner.filter;
 
+import android.media.tv.tuner.Tuner.Filter;
+
 /**
- * Download event.
+ * Filter event sent from {@link Filter} objects with download type.
+ *
  * @hide
  */
 public class DownloadEvent extends FilterEvent {
-    private int mItemId;
-    private int mMpuSequenceNumber;
-    private int mItemFragmentIndex;
-    private int mLastItemFragmentIndex;
-    private int mDataLength;
+    private final int mItemId;
+    private final int mMpuSequenceNumber;
+    private final int mItemFragmentIndex;
+    private final int mLastItemFragmentIndex;
+    private final int mDataLength;
+
+    // This constructor is used by JNI code only
+    private DownloadEvent(int itemId, int mpuSequenceNumber, int itemFragmentIndex,
+            int lastItemFragmentIndex, int dataLength) {
+        mItemId = itemId;
+        mMpuSequenceNumber = mpuSequenceNumber;
+        mItemFragmentIndex = itemFragmentIndex;
+        mLastItemFragmentIndex = lastItemFragmentIndex;
+        mDataLength = dataLength;
+    }
+
+    /**
+     * Gets item ID.
+     */
+    public int getItemId() {
+        return mItemId;
+    }
+
+    /**
+     * Gets MPU sequence number of filtered data.
+     */
+    public int getMpuSequenceNumber() {
+        return mMpuSequenceNumber;
+    }
+
+    /**
+     * Gets current index of the current item.
+     *
+     * An item can be stored in different fragments.
+     */
+    public int getItemFragmentIndex() {
+        return mItemFragmentIndex;
+    }
+
+    /**
+     * Gets last index of the current item.
+     */
+    public int getLastItemFragmentIndex() {
+        return mLastItemFragmentIndex;
+    }
+
+    /**
+     * Gets data size in bytes of filtered data.
+     */
+    public int getDataLength() {
+        return mDataLength;
+    }
 }
 
diff --git a/media/java/android/media/tv/tuner/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
similarity index 70%
rename from media/java/android/media/tv/tuner/Filter.java
rename to media/java/android/media/tv/tuner/filter/Filter.java
index db3b97a..804c0c5 100644
--- a/media/java/android/media/tv/tuner/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -14,33 +14,33 @@
  * limitations under the License.
  */
 
-package android.media.tv.tuner;
+package android.media.tv.tuner.filter;
 
+import android.annotation.BytesLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.media.tv.tuner.Tuner.FilterCallback;
-import android.media.tv.tuner.filter.FilterConfiguration;
-import android.media.tv.tuner.filter.Settings;
 
 /**
  * Tuner data filter.
  *
- * <p> This class is used to filter wanted data according to the filter's configuration.
+ * <p>This class is used to filter wanted data according to the filter's configuration.
+ *
  * @hide
  */
 public class Filter implements AutoCloseable {
     private long mNativeContext;
     private FilterCallback mCallback;
-    int mId;
+    private final int mId;
 
     private native int nativeConfigureFilter(
             int type, int subType, FilterConfiguration settings);
     private native int nativeGetId();
-    private native int nativeSetDataSource(Tuner.Filter source);
+    private native int nativeSetDataSource(Filter source);
     private native int nativeStartFilter();
     private native int nativeStopFilter();
     private native int nativeFlushFilter();
-    private native int nativeRead(byte[] buffer, int offset, int size);
+    private native int nativeRead(byte[] buffer, long offset, long size);
     private native int nativeClose();
 
     private Filter(int id) {
@@ -53,24 +53,20 @@
     /**
      * Configures the filter.
      *
-     * @param settings the settings of the filter.
+     * @param config the configuration of the filter.
      * @return result status of the operation.
-     * @hide
      */
-    public int configure(FilterConfiguration settings) {
+    public int configure(@NonNull FilterConfiguration config) {
         int subType = -1;
-        Settings s = settings.getSettings();
+        Settings s = config.getSettings();
         if (s != null) {
             subType = s.getType();
         }
-        return nativeConfigureFilter(settings.getType(), subType, settings);
+        return nativeConfigureFilter(config.getType(), subType, config);
     }
 
     /**
      * Gets the filter Id.
-     *
-     * @return the hardware resource Id for the filter.
-     * @hide
      */
     public int getId() {
         return nativeGetId();
@@ -87,17 +83,15 @@
      * @param source the filter instance which provides data input. Switch to
      * use demux as data source if the filter instance is NULL.
      * @return result status of the operation.
-     * @hide
      */
-    public int setDataSource(@Nullable Tuner.Filter source) {
+    public int setDataSource(@Nullable Filter source) {
         return nativeSetDataSource(source);
     }
 
     /**
-     * Starts the filter.
+     * Starts filtering data.
      *
      * @return result status of the operation.
-     * @hide
      */
     public int start() {
         return nativeStartFilter();
@@ -105,35 +99,38 @@
 
 
     /**
-     * Stops the filter.
+     * Stops filtering data.
      *
      * @return result status of the operation.
-     * @hide
      */
     public int stop() {
         return nativeStopFilter();
     }
 
     /**
-     * Flushes the filter.
+     * Flushes the filter. Data in filter buffer is cleared.
      *
      * @return result status of the operation.
-     * @hide
      */
     public int flush() {
         return nativeFlushFilter();
     }
 
-    /** @hide */
-    public int read(@NonNull byte[] buffer, int offset, int size) {
+    /**
+     * Copies filtered data from filter buffer to the given byte array.
+     *
+     * @param buffer the buffer to store the filtered data.
+     * @param offset the index of the first byte in {@code buffer} to write.
+     * @param size the maximum number of bytes to read.
+     * @return the number of bytes read.
+     */
+    public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
         size = Math.min(size, buffer.length - offset);
         return nativeRead(buffer, offset, size);
     }
 
     /**
-     * Release the Filter instance.
-     *
-     * @hide
+     * Releases the Filter instance.
      */
     @Override
     public void close() {
diff --git a/media/java/android/media/tv/tuner/filter/IpPayloadEvent.java b/media/java/android/media/tv/tuner/filter/IpPayloadEvent.java
index 4da1d21..09489ed 100644
--- a/media/java/android/media/tv/tuner/filter/IpPayloadEvent.java
+++ b/media/java/android/media/tv/tuner/filter/IpPayloadEvent.java
@@ -16,10 +16,25 @@
 
 package android.media.tv.tuner.filter;
 
+import android.media.tv.tuner.Tuner.Filter;
+
 /**
- * IP payload event.
+ * Filter event sent from {@link Filter} objects with IP payload type.
+ *
  * @hide
  */
 public class IpPayloadEvent extends FilterEvent {
-    private int mDataLength;
+    private final int mDataLength;
+
+    // This constructor is used by JNI code only
+    private IpPayloadEvent(int dataLength) {
+        mDataLength = dataLength;
+    }
+
+    /**
+     * Gets data size in bytes of filtered data.
+     */
+    public int getDataLength() {
+        return mDataLength;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 7703248..37f94ae 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -16,20 +16,111 @@
 
 package android.media.tv.tuner.filter;
 
-import android.os.NativeHandle;
+import android.annotation.Nullable;
+import android.media.tv.tuner.Tuner.Filter;
 
 /**
- * Media event.
+ * Filter event sent from {@link Filter} objects with media type.
+ *
  * @hide
  */
-public class MediaEvent extends FilterEvent {
-    private int mStreamId;
-    private boolean mIsPtsPresent;
-    private long mPts;
-    private int mDataLength;
-    private NativeHandle mHandle;
-    private boolean mIsSecureMemory;
-    private int mMpuSequenceNumber;
-    private boolean mIsPrivateData;
-    private AudioExtraMetaData mExtraMetaData;
+public class MediaEvent extends FilterEvent{
+    private final int mStreamId;
+    private final boolean mIsPtsPresent;
+    private final long mPts;
+    private final int mDataLength;
+    private final Object mLinearBuffer;
+    private final boolean mIsSecureMemory;
+    private final int mMpuSequenceNumber;
+    private final boolean mIsPrivateData;
+    private final AudioDescriptor mExtraMetaData;
+
+    // This constructor is used by JNI code only
+    private MediaEvent(int streamId, boolean isPtsPresent, long pts, int dataLength, Object buffer,
+            boolean isSecureMemory, int mpuSequenceNumber, boolean isPrivateData,
+            AudioDescriptor extraMetaData) {
+        mStreamId = streamId;
+        mIsPtsPresent = isPtsPresent;
+        mPts = pts;
+        mDataLength = dataLength;
+        mLinearBuffer = buffer;
+        mIsSecureMemory = isSecureMemory;
+        mMpuSequenceNumber = mpuSequenceNumber;
+        mIsPrivateData = isPrivateData;
+        mExtraMetaData = extraMetaData;
+    }
+
+    /**
+     * Gets stream ID.
+     */
+    public int getStreamId() {
+        return mStreamId;
+    }
+
+    /**
+     * Returns whether PTS is present.
+     *
+     * @return {@code true} if PTS is present in PES header; {@code false} otherwise.
+     */
+    public boolean getIsPtsPresent() {
+        return mIsPtsPresent;
+    }
+
+    /**
+     * Gets PTS (Presentation Time Stamp) for audio or video frame.
+     */
+    public long getPts() {
+        return mPts;
+    }
+
+    /**
+     * Gets data size in bytes of audio or video frame.
+     */
+    public int getDataLength() {
+        return mDataLength;
+    }
+
+    /**
+     * Gets a linear buffer associated to the memory where audio or video data stays.
+     * TODO: use LinearBuffer when it's ready.
+     *
+     * @hide
+     */
+    public Object getLinearBuffer() {
+        return mLinearBuffer;
+    }
+
+    /**
+     * Returns whether the data is secure.
+     *
+     * @return {@code true} if the data is in secure area, and isn't mappable;
+     *         {@code false} otherwise.
+     */
+    public boolean getIsSecureMemory() {
+        return mIsSecureMemory;
+    }
+
+    /**
+     * Gets MPU sequence number of filtered data.
+     */
+    public int getMpuSequenceNumber() {
+        return mMpuSequenceNumber;
+    }
+
+    /**
+     * Returns whether the data is private.
+     *
+     * @return {@code true} if the data is in private; {@code false} otherwise.
+     */
+    public boolean getIsPrivateData() {
+        return mIsPrivateData;
+    }
+
+    /**
+     * Gets audio extra metadata.
+     */
+    @Nullable
+    public AudioDescriptor getExtraMetaData() {
+        return mExtraMetaData;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index dbd8c77..7f37994 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -16,11 +16,34 @@
 
 package android.media.tv.tuner.filter;
 
+import android.media.tv.tuner.Tuner.Filter;
+
 /**
- * MMPT record event.
+ * Filter event sent from {@link Filter} objects with MMTP type.
+ *
  * @hide
  */
 public class MmtpRecordEvent extends FilterEvent {
-    private int mScHevcIndexMask;
-    private long mByteNumber;
+    private final int mScHevcIndexMask;
+    private final long mByteNumber;
+
+    // This constructor is used by JNI code only
+    private MmtpRecordEvent(int scHevcIndexMask, long byteNumber) {
+        mScHevcIndexMask = scHevcIndexMask;
+        mByteNumber = byteNumber;
+    }
+
+    /**
+     * Gets indexes which can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
+     */
+    public int getScHevcIndexMask() {
+        return mScHevcIndexMask;
+    }
+
+    /**
+     * Gets the byte number from beginning of the filter's output.
+     */
+    public long getByteNumber() {
+        return mByteNumber;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/PesEvent.java b/media/java/android/media/tv/tuner/filter/PesEvent.java
index 16536e2..60251bf 100644
--- a/media/java/android/media/tv/tuner/filter/PesEvent.java
+++ b/media/java/android/media/tv/tuner/filter/PesEvent.java
@@ -16,12 +16,43 @@
 
 package android.media.tv.tuner.filter;
 
+import android.media.tv.tuner.Tuner.Filter;
+
 /**
- * PES event.
+ * Filter event sent from {@link Filter} objects with PES type.
+ *
  * @hide
  */
 public class PesEvent extends FilterEvent {
-    private int mStreamId;
-    private int mDataLength;
-    private int mMpuSequenceNumber;
+    private final int mStreamId;
+    private final int mDataLength;
+    private final int mMpuSequenceNumber;
+
+    // This constructor is used by JNI code only
+    private PesEvent(int streamId, int dataLength, int mpuSequenceNumber) {
+        mStreamId = streamId;
+        mDataLength = dataLength;
+        mMpuSequenceNumber = mpuSequenceNumber;
+    }
+
+    /**
+     * Gets stream ID.
+     */
+    public int getStreamId() {
+        return mStreamId;
+    }
+
+    /**
+     * Gets data size in bytes of filtered data.
+     */
+    public int getDataLength() {
+        return mDataLength;
+    }
+
+    /**
+     * Gets MPU sequence number of filtered data.
+     */
+    public int getMpuSequenceNumber() {
+        return mMpuSequenceNumber;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/TemiEvent.java b/media/java/android/media/tv/tuner/filter/TemiEvent.java
index 3841604..031fa5c 100644
--- a/media/java/android/media/tv/tuner/filter/TemiEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TemiEvent.java
@@ -16,12 +16,46 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.NonNull;
+import android.media.tv.tuner.Tuner.Filter;
+
 /**
- * TEMI event.
+ * Filter event sent from {@link Filter} objects for Timed External Media Information (TEMI) data.
+ *
  * @hide
  */
 public class TemiEvent extends FilterEvent {
-    private long mPts;
-    private byte mDescrTag;
-    private byte[] mDescrData;
+    private final long mPts;
+    private final byte mDescrTag;
+    private final byte[] mDescrData;
+
+    // This constructor is used by JNI code only
+    private TemiEvent(long pts, byte descrTag, byte[] descrData) {
+        mPts = pts;
+        mDescrTag = descrTag;
+        mDescrData = descrData;
+    }
+
+
+    /**
+     * Gets PTS (Presentation Time Stamp) for audio or video frame.
+     */
+    public long getPts() {
+        return mPts;
+    }
+
+    /**
+     * Gets TEMI descriptor tag.
+     */
+    public byte getDescriptorTag() {
+        return mDescrTag;
+    }
+
+    /**
+     * Gets TEMI descriptor.
+     */
+    @NonNull
+    public byte[] getDescriptorData() {
+        return mDescrData;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java
similarity index 98%
rename from media/java/android/media/tv/tuner/TimeFilter.java
rename to media/java/android/media/tv/tuner/filter/TimeFilter.java
index 8bd0d26..c975004 100644
--- a/media/java/android/media/tv/tuner/TimeFilter.java
+++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.tv.tuner;
+package android.media.tv.tuner.filter;
 
 import android.annotation.Nullable;
 import android.media.tv.tuner.TunerConstants.Result;
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index 875b5bd..fa4dd72 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -16,12 +16,84 @@
 
 package android.media.tv.tuner.filter;
 
+import android.annotation.IntDef;
+import android.media.tv.tuner.Tuner.Filter;
+import android.media.tv.tuner.TunerConstants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
- * TS record event.
+ * Filter event sent from {@link Filter} objects for TS record data.
+ *
  * @hide
  */
 public class TsRecordEvent extends FilterEvent {
-    private int mTpid;
-    private int mIndexMask;
-    private long mByteNumber;
+    /**
+     * @hide
+     */
+    @IntDef(flag = true, value = {
+            TunerConstants.TS_INDEX_FIRST_PACKET,
+            TunerConstants.TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+            TunerConstants.TS_INDEX_CHANGE_TO_NOT_SCRAMBLED,
+            TunerConstants.TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
+            TunerConstants.TS_INDEX_CHANGE_TO_ODD_SCRAMBLED,
+            TunerConstants.TS_INDEX_DISCONTINUITY_INDICATOR,
+            TunerConstants.TS_INDEX_RANDOM_ACCESS_INDICATOR,
+            TunerConstants.TS_INDEX_PRIORITY_INDICATOR,
+            TunerConstants.TS_INDEX_PCR_FLAG,
+            TunerConstants.TS_INDEX_OPCR_FLAG,
+            TunerConstants.TS_INDEX_SPLICING_POINT_FLAG,
+            TunerConstants.TS_INDEX_PRIVATE_DATA,
+            TunerConstants.TS_INDEX_ADAPTATION_EXTENSION_FLAG,
+            TunerConstants.SC_INDEX_I_FRAME,
+            TunerConstants.SC_INDEX_P_FRAME,
+            TunerConstants.SC_INDEX_B_FRAME,
+            TunerConstants.SC_INDEX_SEQUENCE,
+            TunerConstants.SC_HEVC_INDEX_SPS,
+            TunerConstants.SC_HEVC_INDEX_AUD,
+            TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+            TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
+            TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
+            TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
+            TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
+            TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IndexMask {}
+
+    private final int mPid;
+    private final int mIndexMask;
+    private final long mByteNumber;
+
+    // This constructor is used by JNI code only
+    private TsRecordEvent(int pid, int indexMask, long byteNumber) {
+        mPid = pid;
+        mIndexMask = indexMask;
+        mByteNumber = byteNumber;
+    }
+
+    /**
+     * Gets packet ID.
+     */
+    public int getTpid() {
+        return mPid;
+    }
+
+    /**
+     * Gets index mask.
+     *
+     * <p>The index type is one of TS, SC, and SC-HEVC, and is set when configuring the filter.
+     */
+    @IndexMask
+    public int getIndexMask() {
+        return mIndexMask;
+    }
+
+    /**
+     * Gets the byte number from beginning of the filter's output.
+     */
+    public long getByteNumber() {
+        return mByteNumber;
+    }
 }
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/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/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/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..e949007 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/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/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/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/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/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
index ebfc2a0..549051d 100644
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
@@ -32,6 +32,7 @@
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.UserManager;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -81,8 +82,15 @@
                     .setImageDrawable(drawable);
         }
 
-        ((TextView) view.findViewById(R.id.user_loading))
-                .setText(res.getString(R.string.car_loading_profile));
+        TextView msgView = view.findViewById(R.id.user_loading);
+        // TODO: use developer settings instead
+        if (Build.IS_DEBUGGABLE) {
+            // TODO: use specific string
+            msgView.setText(res.getString(R.string.car_loading_profile) + " user\n(from "
+                    + mOldUser.id + " to " + mNewUser.id + ")");
+        } else {
+            msgView.setText(res.getString(R.string.car_loading_profile));
+        }
         setView(view);
     }
 
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/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/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index d8c1966..d468cd9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4571,8 +4571,8 @@
 
         @Override
         public void onNewUserCreated(int userId) {
+            mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
             synchronized (mLock) {
-                mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
                 // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
                 PermissionManagerService.this.updateAllPermissions(
                         StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
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/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/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/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/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index aaafee2..f39981f 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import com.android.telephony.Rlog;
-
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index 97bcbc0..a17a19c 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -27,7 +27,7 @@
 import android.os.UserHandle;
 import android.permission.IPermissionManager;
 import android.provider.Settings;
-import com.android.telephony.Rlog;
+import android.util.Log;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -80,7 +80,7 @@
             IPackageManager packageManager, IPermissionManager permissionManager,
             TelephonyManager telephonyManager, int userId, Context context) {
         if (DEBUG) {
-            Rlog.d(TAG, "disableCarrierAppsUntilPrivileged");
+            Log.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
         SystemConfig config = SystemConfig.getInstance();
         ArraySet<String> systemCarrierAppsDisabledUntilUsed =
@@ -108,7 +108,7 @@
             IPackageManager packageManager, IPermissionManager permissionManager, int userId,
             Context context) {
         if (DEBUG) {
-            Rlog.d(TAG, "disableCarrierAppsUntilPrivileged");
+            Log.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
         SystemConfig config = SystemConfig.getInstance();
         ArraySet<String> systemCarrierAppsDisabledUntilUsed =
@@ -187,7 +187,7 @@
                             || ai.enabledSetting
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
                             || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
-                        Rlog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+                        Log.i(TAG, "Update state(" + packageName + "): ENABLED for user "
                                 + userId);
                         packageManager.setSystemAppInstallState(
                                 packageName,
@@ -210,7 +210,7 @@
                                     == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
                                     || (associatedApp.flags
                                     & ApplicationInfo.FLAG_INSTALLED) == 0) {
-                                Rlog.i(TAG, "Update associated state(" + associatedApp.packageName
+                                Log.i(TAG, "Update associated state(" + associatedApp.packageName
                                         + "): ENABLED for user " + userId);
                                 packageManager.setSystemAppInstallState(
                                         associatedApp.packageName,
@@ -235,7 +235,7 @@
                             && ai.enabledSetting
                             == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
-                        Rlog.i(TAG, "Update state(" + packageName
+                        Log.i(TAG, "Update state(" + packageName
                                 + "): DISABLED_UNTIL_USED for user " + userId);
                         packageManager.setSystemAppInstallState(
                                 packageName,
@@ -253,7 +253,7 @@
                                         == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                                         && (associatedApp.flags
                                         & ApplicationInfo.FLAG_INSTALLED) != 0) {
-                                    Rlog.i(TAG,
+                                    Log.i(TAG,
                                             "Update associated state(" + associatedApp.packageName
                                                     + "): DISABLED_UNTIL_USED for user " + userId);
                                     packageManager.setSystemAppInstallState(
@@ -280,7 +280,7 @@
                 permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
             }
         } catch (RemoteException e) {
-            Rlog.w(TAG, "Could not reach PackageManager", e);
+            Log.w(TAG, "Could not reach PackageManager", e);
         }
     }
 
@@ -402,7 +402,7 @@
                 return ai;
             }
         } catch (RemoteException e) {
-            Rlog.w(TAG, "Could not reach PackageManager", e);
+            Log.w(TAG, "Could not reach PackageManager", e);
         }
         return null;
     }
diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
index a36ff93..5c53f7e 100644
--- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
@@ -19,7 +19,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.os.Build;
-import com.android.telephony.Rlog;
+import android.util.Log;
 import android.text.TextUtils;
 import android.util.SparseIntArray;
 
@@ -498,11 +498,11 @@
         StringBuilder ret = new StringBuilder(lengthSeptets);
 
         if (languageTable < 0 || languageTable > sLanguageTables.length) {
-            Rlog.w(TAG, "unknown language table " + languageTable + ", using default");
+            Log.w(TAG, "unknown language table " + languageTable + ", using default");
             languageTable = 0;
         }
         if (shiftTable < 0 || shiftTable > sLanguageShiftTables.length) {
-            Rlog.w(TAG, "unknown single shift table " + shiftTable + ", using default");
+            Log.w(TAG, "unknown single shift table " + shiftTable + ", using default");
             shiftTable = 0;
         }
 
@@ -512,11 +512,11 @@
             String shiftTableToChar = sLanguageShiftTables[shiftTable];
 
             if (languageTableToChar.isEmpty()) {
-                Rlog.w(TAG, "no language table for code " + languageTable + ", using default");
+                Log.w(TAG, "no language table for code " + languageTable + ", using default");
                 languageTableToChar = sLanguageTables[0];
             }
             if (shiftTableToChar.isEmpty()) {
-                Rlog.w(TAG, "no single shift table for code " + shiftTable + ", using default");
+                Log.w(TAG, "no single shift table for code " + shiftTable + ", using default");
                 shiftTableToChar = sLanguageShiftTables[0];
             }
 
@@ -556,7 +556,7 @@
                 }
             }
         } catch (RuntimeException ex) {
-            Rlog.e(TAG, "Error GSM 7 bit packed: ", ex);
+            Log.e(TAG, "Error GSM 7 bit packed: ", ex);
             return null;
         }
 
@@ -813,7 +813,7 @@
         for (int i = 0; i < sz; i++) {
             char c = s.charAt(i);
             if (c == GSM_EXTENDED_ESCAPE) {
-                Rlog.w(TAG, "countGsmSeptets() string contains Escape character, skipping.");
+                Log.w(TAG, "countGsmSeptets() string contains Escape character, skipping.");
                 continue;
             }
             if (charToLanguageTable.get(c, -1) != -1) {
@@ -892,7 +892,7 @@
         for (int i = 0; i < sz && !lpcList.isEmpty(); i++) {
             char c = s.charAt(i);
             if (c == GSM_EXTENDED_ESCAPE) {
-                Rlog.w(TAG, "countGsmSeptets() string contains Escape character, ignoring!");
+                Log.w(TAG, "countGsmSeptets() string contains Escape character, ignoring!");
                 continue;
             }
             // iterate through enabled locking shift tables
@@ -1496,7 +1496,7 @@
         int numTables = sLanguageTables.length;
         int numShiftTables = sLanguageShiftTables.length;
         if (numTables != numShiftTables) {
-            Rlog.e(TAG, "Error: language tables array length " + numTables +
+            Log.e(TAG, "Error: language tables array length " + numTables +
                     " != shift tables array length " + numShiftTables);
         }
 
@@ -1506,7 +1506,7 @@
 
             int tableLen = table.length();
             if (tableLen != 0 && tableLen != 128) {
-                Rlog.e(TAG, "Error: language tables index " + i +
+                Log.e(TAG, "Error: language tables index " + i +
                         " length " + tableLen + " (expected 128 or 0)");
             }
 
@@ -1524,7 +1524,7 @@
 
             int shiftTableLen = shiftTable.length();
             if (shiftTableLen != 0 && shiftTableLen != 128) {
-                Rlog.e(TAG, "Error: language shift tables index " + i +
+                Log.e(TAG, "Error: language shift tables index " + i +
                         " length " + shiftTableLen + " (expected 128 or 0)");
             }
 
diff --git a/telephony/common/com/android/internal/telephony/HbpcdUtils.java b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
index 45a563c..714f5a6 100644
--- a/telephony/common/com/android/internal/telephony/HbpcdUtils.java
+++ b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
@@ -19,7 +19,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
-import com.android.telephony.Rlog;
+import android.util.Log;
 
 import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
 import com.android.internal.telephony.HbpcdLookup.MccIdd;
@@ -54,16 +54,16 @@
         if (c2 != null) {
             int c2Counter = c2.getCount();
             if (DBG) {
-                Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
+                Log.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
             }
             if (c2Counter == 1) {
                 if (DBG) {
-                    Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
+                    Log.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
                 }
                 c2.moveToFirst();
                 tmpMcc = c2.getInt(0);
                 if (DBG) {
-                    Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
+                    Log.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
                 }
                 c2.close();
                 return tmpMcc;
@@ -85,18 +85,18 @@
             int c3Counter = c3.getCount();
             if (c3Counter > 0) {
                 if (c3Counter > 1) {
-                    Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
+                    Log.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
                 }
-                if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
+                if (DBG) Log.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
                 c3.moveToFirst();
                 tmpMcc = c3.getInt(0);
                 if (DBG) {
-                    Rlog.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
+                    Log.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
                 }
                 if (!isNitzTimeZone) {
                     // time zone is not accurate, it may get wrong mcc, ignore it.
                     if (DBG) {
-                        Rlog.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc);
+                        Log.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc);
                     }
                     tmpMcc = 0;
                 }
@@ -115,18 +115,18 @@
                 null, null);
         if (c5 != null) {
             if (c5.getCount() > 0) {
-                if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5);
+                if (DBG) Log.d(LOG_TAG, "Query Range returned the cursor " + c5);
                 c5.moveToFirst();
                 tmpMcc = c5.getInt(0);
-                if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
+                if (DBG) Log.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
                 c5.close();
                 return tmpMcc;
             }
             c5.close();
         }
-        if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
+        if (DBG) Log.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
 
-        if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc =  " + tmpMcc);
+        if (DBG) Log.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc =  " + tmpMcc);
         // If unknown MCC still could not be resolved,
         return tmpMcc;
     }
@@ -135,7 +135,7 @@
      *  Gets country information with given MCC.
     */
     public String getIddByMcc(int mcc) {
-        if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
+        if (DBG) Log.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
         String idd = "";
 
         Cursor c = null;
@@ -145,19 +145,19 @@
                 MccIdd.MCC + "=" + mcc, null, null);
         if (cur != null) {
             if (cur.getCount() > 0) {
-                if (DBG) Rlog.d(LOG_TAG, "Query Idd returned the cursor " + cur);
+                if (DBG) Log.d(LOG_TAG, "Query Idd returned the cursor " + cur);
                 // TODO: for those country having more than 1 IDDs, need more information
                 // to decide which IDD would be used. currently just use the first 1.
                 cur.moveToFirst();
                 idd = cur.getString(0);
-                if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd);
+                if (DBG) Log.d(LOG_TAG, "IDD = " + idd);
 
             }
             cur.close();
         }
         if (c != null) c.close();
 
-        if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
+        if (DBG) Log.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
         return idd;
     }
 }
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index afb9b6f..9b82828 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -40,7 +40,7 @@
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.PackageChangeReceiver;
-import com.android.telephony.Rlog;
+import android.util.Log;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
@@ -565,7 +565,7 @@
             int mode = appOps.unsafeCheckOp(opStr, applicationData.mUid,
                     applicationData.mPackageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
-                Rlog.e(LOG_TAG, applicationData.mPackageName + " lost "
+                Log.e(LOG_TAG, applicationData.mPackageName + " lost "
                         + opStr + ": "
                         + (updateIfNeeded ? " (fixing)" : " (no permission to fix)"));
                 if (updateIfNeeded) {
@@ -643,7 +643,7 @@
                     int uid = packageManager.getPackageInfo(oldPackageName, 0).applicationInfo.uid;
                     setExclusiveAppops(oldPackageName, appOps, uid, AppOpsManager.MODE_DEFAULT);
                 } catch (NameNotFoundException e) {
-                    Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName);
+                    Log.w(LOG_TAG, "Old SMS package not found: " + oldPackageName);
                 }
             }
 
@@ -750,7 +750,7 @@
         // the package signature matches system signature.
         final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
         if (result != PackageManager.SIGNATURE_MATCH) {
-            Rlog.e(LOG_TAG, packageName + " does not have system signature");
+            Log.e(LOG_TAG, packageName + " does not have system signature");
             return;
         }
         try {
@@ -758,13 +758,13 @@
             int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid,
                     packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
-                Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS:  (fixing)");
+                Log.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS:  (fixing)");
                 setExclusiveAppops(packageName, appOps, info.applicationInfo.uid,
                         AppOpsManager.MODE_ALLOWED);
             }
         } catch (NameNotFoundException e) {
             // No whitelisted system app on this device
-            Rlog.e(LOG_TAG, "Package not found: " + packageName);
+            Log.e(LOG_TAG, "Package not found: " + packageName);
         }
 
     }
diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
index 06c3728..cd365a1 100644
--- a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
+++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
@@ -24,13 +24,16 @@
 import android.os.SystemProperties;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import com.android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
 
 import com.android.internal.telephony.HbpcdLookup.MccIdd;
 import com.android.internal.telephony.HbpcdLookup.MccLookup;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -143,7 +146,7 @@
 
         // First check whether the number is a NANP number.
         int nanpState = checkNANP(numberEntry, allIDDs);
-        if (DBG) Rlog.d(TAG, "NANP type: " + getNumberPlanType(nanpState));
+        if (DBG) Log.d(TAG, "NANP type: " + getNumberPlanType(nanpState));
 
         if ((nanpState == NP_NANP_LOCAL)
             || (nanpState == NP_NANP_AREA_LOCAL)
@@ -173,7 +176,7 @@
 
         int internationalState = checkInternationalNumberPlan(context, numberEntry, allIDDs,
                 NANP_IDD);
-        if (DBG) Rlog.d(TAG, "International type: " + getNumberPlanType(internationalState));
+        if (DBG) Log.d(TAG, "International type: " + getNumberPlanType(internationalState));
         String returnNumber = null;
 
         switch (internationalState) {
@@ -272,7 +275,7 @@
                 }
             }
         } catch (SQLException e) {
-            Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+            Log.e(TAG, "Can't access HbpcdLookup database", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -281,7 +284,7 @@
 
         IDDS_MAPS.put(mcc, allIDDs);
 
-        if (DBG) Rlog.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs);
+        if (DBG) Log.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs);
         return allIDDs;
     }
 
@@ -472,7 +475,7 @@
                 int tempCC = allCCs[i];
                 for (int j = 0; j < MAX_COUNTRY_CODES_LENGTH; j ++) {
                     if (tempCC == ccArray[j]) {
-                        if (DBG) Rlog.d(TAG, "Country code = " + tempCC);
+                        if (DBG) Log.d(TAG, "Country code = " + tempCC);
                         return tempCC;
                     }
                 }
@@ -509,7 +512,7 @@
                 }
             }
         } catch (SQLException e) {
-            Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+            Log.e(TAG, "Can't access HbpcdLookup database", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -561,10 +564,10 @@
      * Filter the destination number if using VZW sim card.
      */
     public static String filterDestAddr(Context context, int subId, String destAddr) {
-        if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" );
+        if (DBG) Log.d(TAG, "enter filterDestAddr. destAddr=\"" + pii(TAG, destAddr) + "\"" );
 
         if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) {
-            Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) +
+            Log.w(TAG, "destAddr" + pii(TAG, destAddr) +
                     " is not a global phone number! Nothing changed.");
             return destAddr;
         }
@@ -585,9 +588,9 @@
         }
 
         if (DBG) {
-            Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
-            Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG,
-                    result) : Rlog.pii(TAG, destAddr)) + "\"");
+            Log.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
+            Log.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? pii(TAG,
+                    result) : pii(TAG, destAddr)) + "\"");
         }
         return result != null ? result : destAddr;
     }
@@ -608,7 +611,7 @@
                 networkType = CDMA_HOME_NETWORK;
             }
         } else {
-            if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType);
+            if (DBG) Log.w(TAG, "warning! unknown mPhoneType value=" + phoneType);
         }
 
         return networkType;
@@ -650,4 +653,44 @@
         // by default this value is false
         return false;
     }
+
+    /**
+     * Redact personally identifiable information for production users.
+     * @param tag used to identify the source of a log message
+     * @param pii the personally identifiable information we want to apply secure hash on.
+     * @return If tag is loggable in verbose mode or pii is null, return the original input.
+     * otherwise return a secure Hash of input pii
+     */
+    private static String pii(String tag, Object pii) {
+        String val = String.valueOf(pii);
+        if (pii == null || TextUtils.isEmpty(val) || Log.isLoggable(tag, Log.VERBOSE)) {
+            return val;
+        }
+        return "[" + secureHash(val.getBytes()) + "]";
+    }
+
+    /**
+     * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+     *
+     * @return "****" if the build type is user, otherwise the hash
+     * @param input the bytes for which the secure hash should be computed.
+     */
+    private static String secureHash(byte[] input) {
+        // Refrain from logging user personal information in user build.
+        if (android.os.Build.IS_USER) {
+            return "****";
+        }
+
+        MessageDigest messageDigest;
+
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            return "####";
+        }
+
+        byte[] result = messageDigest.digest(input);
+        return Base64.encodeToString(
+                result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+    }
 }
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 4109ca6..f6ce0dc 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -28,7 +28,6 @@
 import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
-import com.android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -521,7 +520,7 @@
             return;
         }
 
-        if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
+        if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next.");
         enforceCallingOrSelfCarrierPrivilege(context, subId, message);
     }
 
@@ -539,7 +538,7 @@
         }
 
         if (DBG) {
-            Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
+            Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
         }
 
         enforceCallingOrSelfCarrierPrivilege(context, subId, message);
@@ -559,7 +558,7 @@
         }
 
         if (DBG) {
-            Rlog.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, "
+            Log.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, "
                     + "check carrier privilege next.");
         }
 
@@ -584,7 +583,7 @@
             Context context, int subId, int uid, String message) {
         if (getCarrierPrivilegeStatus(context, subId, uid)
                 != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-            if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
+            if (DBG) Log.e(LOG_TAG, "No Carrier Privilege.");
             throw new SecurityException(message);
         }
     }
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/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/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/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;
+    }
+}