Merge changes from topic "api-review-getNetworkDisableReasonString" into rvc-dev

* changes:
  Settings: Rename NetworkSelectionStatus#getNetworkDisableReasonString
  Rename NetworkSelectionStatus#getNetworkDisableReasonString
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 11d3a68..566f4cd 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -1114,20 +1114,22 @@
     static {
         // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
         LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
-        extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new);
-        extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new);
-        extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new);
-        extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new);
-        extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new);
-        extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new);
-        extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new);
+        // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering,
+        // which in turn aims to minimize the chances of incorrect extractor selections.
         extractorFactoriesByName.put("exo.MatroskaParser", MatroskaExtractor::new);
-        extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new);
+        extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new);
         extractorFactoriesByName.put("exo.Mp4Parser", Mp4Extractor::new);
+        extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new);
+        extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new);
+        extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new);
+        extractorFactoriesByName.put("exo.TsParser", TsExtractor::new);
+        extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new);
         extractorFactoriesByName.put("exo.OggParser", OggExtractor::new);
         extractorFactoriesByName.put("exo.PsParser", PsExtractor::new);
-        extractorFactoriesByName.put("exo.TsParser", TsExtractor::new);
         extractorFactoriesByName.put("exo.WavParser", WavExtractor::new);
+        extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new);
+        extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new);
+        extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new);
         EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
 
         HashMap<String, Class> expectedTypeByParameterName = new HashMap<>();
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 205ffc2..30a8b45 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -246,7 +246,7 @@
                     permissionState.isGranted() && (permissionState.getFlags()
                             & PackageManager.FLAG_PERMISSION_ONE_TIME) == 0));
             serializer.attribute(null, ATTRIBUTE_FLAGS, Integer.toHexString(
-                    permissionState.getFlags() & ~PackageManager.FLAG_PERMISSION_ONE_TIME));
+                    permissionState.getFlags()));
             serializer.endTag(null, TAG_PERMISSION);
         }
     }
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 cb167c3..dc61f2ae 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -21,11 +21,13 @@
 import android.app.AlarmManager.OnAlarmListener;
 import android.app.StatsManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -85,12 +87,6 @@
 
     public static final int DEATH_THRESHOLD = 10;
 
-    // TODO(b/149090705): Implement an alternative to sending broadcast with @hide flag
-    // FLAG_RECEIVER_INCLUDE_BACKGROUND. Instead of using the flag, find the
-    // list of registered broadcast receivers and send them directed broadcasts
-    // to wake them up. See b/147374337.
-    private static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
-
     static final class CompanionHandler extends Handler {
         CompanionHandler(Looper looper) {
             super(looper);
@@ -498,9 +494,25 @@
             Log.d(TAG, "learned that statsdReady");
         }
         sayHiToStatsd(); // tell statsd that we're ready too and link to it
-        mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)
-                        .addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND),
-                UserHandle.SYSTEM, android.Manifest.permission.DUMP);
+
+        final Intent intent = new Intent(StatsManager.ACTION_STATSD_STARTED);
+        // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts
+        // to wake them up (if they're in background).
+        List<ResolveInfo> resolveInfos =
+                mContext.getPackageManager().queryBroadcastReceiversAsUser(
+                        intent, 0, UserHandle.SYSTEM);
+        if (resolveInfos == null || resolveInfos.isEmpty()) {
+            return; // No need to send broadcast.
+        }
+
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            Intent intentToSend = new Intent(intent);
+            intentToSend.setComponent(new ComponentName(
+                    resolveInfo.activityInfo.applicationInfo.packageName,
+                    resolveInfo.activityInfo.name));
+            mContext.sendBroadcastAsUser(intentToSend, UserHandle.SYSTEM,
+                    android.Manifest.permission.DUMP);
+        }
     }
 
     @Override
diff --git a/api/current.txt b/api/current.txt
index 6e9f7c3..1bd3aa7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8189,6 +8189,7 @@
     field public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
     field public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
     field public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
+    field public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
   }
 
   public class AppWidgetProvider extends android.content.BroadcastReceiver {
@@ -31105,6 +31106,7 @@
 
   public class ScanResult implements android.os.Parcelable {
     ctor public ScanResult(@NonNull android.net.wifi.ScanResult);
+    ctor public ScanResult();
     method public int describeContents();
     method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getInformationElements();
     method public int getWifiStandard();
@@ -31376,6 +31378,15 @@
     field public static final int LINK_SPEED_UNKNOWN = -1; // 0xffffffff
   }
 
+  public static final class WifiInfo.Builder {
+    ctor public WifiInfo.Builder();
+    method @NonNull public android.net.wifi.WifiInfo build();
+    method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int);
+    method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]);
+  }
+
   public class WifiManager {
     method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
@@ -31559,6 +31570,20 @@
 
   public final class WifiNetworkSuggestion implements android.os.Parcelable {
     method public int describeContents();
+    method @Nullable public android.net.MacAddress getBssid();
+    method @Nullable public android.net.wifi.WifiEnterpriseConfig getEnterpriseConfig();
+    method @Nullable public String getPassphrase();
+    method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
+    method @IntRange(from=0) public int getPriority();
+    method @Nullable public String getSsid();
+    method public boolean isAppInteractionRequired();
+    method public boolean isCredentialSharedWithUser();
+    method public boolean isEnhancedOpen();
+    method public boolean isHiddenSsid();
+    method public boolean isInitialAutojoinEnabled();
+    method public boolean isMetered();
+    method public boolean isUntrusted();
+    method public boolean isUserInteractionRequired();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR;
   }
@@ -48146,6 +48171,7 @@
     method public String getMmsUserAgent();
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNai();
     method public String getNetworkCountryIso();
+    method @NonNull public String getNetworkCountryIso(int);
     method public String getNetworkOperator();
     method public String getNetworkOperatorName();
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode();
diff --git a/api/system-current.txt b/api/system-current.txt
index b6f0b80..63bb7d1 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4944,8 +4944,24 @@
 
 package android.media.tv.tuner.dvr {
 
-  public class Dvr implements java.lang.AutoCloseable {
-    ctor protected Dvr(int);
+  public class DvrPlayback implements java.lang.AutoCloseable {
+    method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+    method public void close();
+    method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
+    method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
+    method public int flush();
+    method public long read(long);
+    method public long read(@NonNull byte[], long, long);
+    method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
+    method public int start();
+    method public int stop();
+    field public static final int PLAYBACK_STATUS_ALMOST_EMPTY = 2; // 0x2
+    field public static final int PLAYBACK_STATUS_ALMOST_FULL = 4; // 0x4
+    field public static final int PLAYBACK_STATUS_EMPTY = 1; // 0x1
+    field public static final int PLAYBACK_STATUS_FULL = 8; // 0x8
+  }
+
+  public class DvrRecorder implements java.lang.AutoCloseable {
     method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
     method public void close();
     method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
@@ -4954,20 +4970,6 @@
     method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
     method public int start();
     method public int stop();
-    field public static final int TYPE_PLAYBACK = 1; // 0x1
-    field public static final int TYPE_RECORD = 0; // 0x0
-  }
-
-  public class DvrPlayback extends android.media.tv.tuner.dvr.Dvr {
-    method public long read(long);
-    method public long read(@NonNull byte[], long, long);
-    field public static final int PLAYBACK_STATUS_ALMOST_EMPTY = 2; // 0x2
-    field public static final int PLAYBACK_STATUS_ALMOST_FULL = 4; // 0x4
-    field public static final int PLAYBACK_STATUS_EMPTY = 1; // 0x1
-    field public static final int PLAYBACK_STATUS_FULL = 8; // 0x8
-  }
-
-  public class DvrRecorder extends android.media.tv.tuner.dvr.Dvr {
     method public long write(long);
     method public long write(@NonNull byte[], long, long);
   }
@@ -7169,7 +7171,6 @@
   }
 
   public class ScanResult implements android.os.Parcelable {
-    ctor public ScanResult();
     field public static final int CIPHER_CCMP = 3; // 0x3
     field public static final int CIPHER_GCMP_256 = 4; // 0x4
     field public static final int CIPHER_NONE = 0; // 0x0
@@ -7377,15 +7378,6 @@
     field public static final int INVALID_RSSI = -127; // 0xffffff81
   }
 
-  public static final class WifiInfo.Builder {
-    ctor public WifiInfo.Builder();
-    method @NonNull public android.net.wifi.WifiInfo build();
-    method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String);
-    method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int);
-    method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int);
-    method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]);
-  }
-
   public class WifiManager {
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
@@ -7528,7 +7520,7 @@
   }
 
   public static interface WifiManager.ScoreChangeCallback {
-    method public void onScoreChange(int, @NonNull android.net.NetworkScore);
+    method public void onScoreChange(int, int);
     method public void onTriggerUpdateOfWifiUsabilityStats(int);
   }
 
@@ -7554,6 +7546,52 @@
     method public void stop(int);
   }
 
+  public final class WifiMigration {
+    method @Nullable public static android.net.wifi.WifiMigration.ConfigStoreMigrationData loadFromConfigStore();
+    method @NonNull public static android.net.wifi.WifiMigration.SettingsMigrationData loadFromSettings(@NonNull android.content.Context);
+    method public static void removeConfigStore();
+  }
+
+  public static final class WifiMigration.ConfigStoreMigrationData 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.WifiMigration.ConfigStoreMigrationData> CREATOR;
+  }
+
+  public static final class WifiMigration.ConfigStoreMigrationData.Builder {
+    ctor public WifiMigration.ConfigStoreMigrationData.Builder();
+    method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData build();
+    method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>);
+    method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+  }
+
+  public static final class WifiMigration.SettingsMigrationData implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getP2pDeviceName();
+    method public boolean isP2pFactoryResetPending();
+    method public boolean isScanAlwaysAvailable();
+    method public boolean isScanThrottleEnabled();
+    method public boolean isSoftApTimeoutEnabled();
+    method public boolean isVerboseLoggingEnabled();
+    method public boolean isWakeUpEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiMigration.SettingsMigrationData> CREATOR;
+  }
+
+  public static final class WifiMigration.SettingsMigrationData.Builder {
+    ctor public WifiMigration.SettingsMigrationData.Builder();
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData build();
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanThrottleEnabled(boolean);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean);
+    method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setWakeUpEnabled(boolean);
+  }
+
   public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
     ctor public WifiNetworkConnectionStatistics(int, int);
     ctor public WifiNetworkConnectionStatistics();
@@ -7570,7 +7608,6 @@
   }
 
   public final class WifiNetworkSuggestion implements android.os.Parcelable {
-    method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfiguration();
     method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
   }
 
@@ -7578,51 +7615,6 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
   }
 
-  public final class WifiOemMigrationHook {
-    method @Nullable public static android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData loadFromConfigStore();
-    method @NonNull public static android.net.wifi.WifiOemMigrationHook.SettingsMigrationData loadFromSettings(@NonNull android.content.Context);
-  }
-
-  public static final class WifiOemMigrationHook.ConfigStoreMigrationData 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.WifiOemMigrationHook.ConfigStoreMigrationData> CREATOR;
-  }
-
-  public static final class WifiOemMigrationHook.ConfigStoreMigrationData.Builder {
-    ctor public WifiOemMigrationHook.ConfigStoreMigrationData.Builder();
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData build();
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
-  }
-
-  public static final class WifiOemMigrationHook.SettingsMigrationData implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public String getP2pDeviceName();
-    method public boolean isP2pFactoryResetPending();
-    method public boolean isScanAlwaysAvailable();
-    method public boolean isScanThrottleEnabled();
-    method public boolean isSoftApTimeoutEnabled();
-    method public boolean isVerboseLoggingEnabled();
-    method public boolean isWakeUpEnabled();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemMigrationHook.SettingsMigrationData> CREATOR;
-  }
-
-  public static final class WifiOemMigrationHook.SettingsMigrationData.Builder {
-    ctor public WifiOemMigrationHook.SettingsMigrationData.Builder();
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData build();
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanThrottleEnabled(boolean);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean);
-    method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setWakeUpEnabled(boolean);
-  }
-
   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);
@@ -11738,7 +11730,6 @@
     method public int getMaxNumberOfSimultaneouslyActiveSims();
     method public static long getMaxNumberVerificationTimeoutMillis();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup();
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
     method public int getSimApplicationState();
@@ -11796,7 +11787,6 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAlwaysAllowMmsData(boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull android.telephony.CallForwardingInfo);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
@@ -11811,7 +11801,6 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(@NonNull String, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPolicyDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4a9c4d6..0f8694f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3769,7 +3769,6 @@
     method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method public int getEmergencyNumberDbVersion();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
-    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int);
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 95de6c5..1e200c5 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -146,6 +146,8 @@
     struct uhid_event ev = {};
     ev.type = UHID_CREATE2;
     strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
+    std::string uniq = android::base::StringPrintf("Id: %d", id);
+    strlcpy(reinterpret_cast<char*>(ev.u.create2.uniq), uniq.c_str(), sizeof(ev.u.create2.uniq));
     memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0]));
     ev.u.create2.rd_size = size;
     ev.u.create2.bus = bus;
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 0b0541f..d4e888f 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -31,6 +31,7 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/Policies.h"
 #include "idmap2/SysTrace.h"
+#include "Commands.h"
 
 using android::ApkAssets;
 using android::base::StringPrintf;
@@ -105,32 +106,34 @@
       continue;
     }
 
-    const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
-    if (!overlay_apk) {
-      LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
-      continue;
-    }
+    if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}))) {
+      const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+      if (!overlay_apk) {
+        LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
+        continue;
+      }
 
-    const auto idmap =
-        Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, !ignore_overlayable);
-    if (!idmap) {
-      LOG(WARNING) << "failed to create idmap";
-      continue;
-    }
+      const auto idmap =
+          Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, !ignore_overlayable);
+      if (!idmap) {
+        LOG(WARNING) << "failed to create idmap";
+        continue;
+      }
 
-    umask(kIdmapFilePermissionMask);
-    std::ofstream fout(idmap_path);
-    if (fout.fail()) {
-      LOG(WARNING) << "failed to open idmap path " << idmap_path.c_str();
-      continue;
-    }
+      umask(kIdmapFilePermissionMask);
+      std::ofstream fout(idmap_path);
+      if (fout.fail()) {
+        LOG(WARNING) << "failed to open idmap path " << idmap_path.c_str();
+        continue;
+      }
 
-    BinaryStreamVisitor visitor(fout);
-    (*idmap)->accept(&visitor);
-    fout.close();
-    if (fout.fail()) {
-      LOG(WARNING) << "failed to write to idmap path %s" << idmap_path.c_str();
-      continue;
+      BinaryStreamVisitor visitor(fout);
+      (*idmap)->accept(&visitor);
+      fout.close();
+      if (fout.fail()) {
+        LOG(WARNING) << "failed to write to idmap path %s" << idmap_path.c_str();
+        continue;
+      }
     }
 
     idmap_paths.emplace_back(idmap_path);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2575542..f36b855 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -393,6 +393,8 @@
         WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
         AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"];
         SnapshotMergeReported snapshot_merge_reported = 255;
+        ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended =
+            256  [(module) = "framework"];
         SdkExtensionStatus sdk_extension_status = 354;
     }
 
@@ -3285,12 +3287,12 @@
     ];
 }
 
-/*
+/**
  * Logs foreground service starts and stops.
  * Note that this is not when a service starts or stops, but when it is
  * considered foreground.
  * Logged from
- *     //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
+ *     frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
  */
 message ForegroundServiceStateChanged {
     optional int32 uid = 1 [(is_uid) = true];
@@ -3302,6 +3304,49 @@
         EXIT = 2;
     }
     optional State state = 3;
+
+    // Whether the fgs is allowed while-in-use permissions, i.e. is considered 'in-use' to the user.
+    // (If the fgs was started while the app wasn't TOP it usually will be denied these permissions)
+    optional bool allow_while_in_use_permission = 4;
+}
+
+/**
+ * Logs the number of times a uid accesses a sensitive AppOp during a foreground service session.
+ * A foreground service session is any continuous period during which the uid holds at least one
+ * foreground service; the atom will be pushed when the uid no longer holds any foreground services.
+ * Accesses initiated while the uid is in the TOP state are ignored.
+ * Sessions with no attempted accesses are not logged.
+ * Logged from
+ *     frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
+ */
+message ForegroundServiceAppOpSessionEnded {
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // The operation's name.
+    // To the extent possible, preserve the mapping from AppOpsManager.OP_ constants.
+    // Only these named ops are actually logged.
+    enum AppOpName {
+        OP_NONE = -1; // Also represents UNKNOWN.
+        OP_COARSE_LOCATION = 0;
+        OP_FINE_LOCATION = 1;
+        OP_CAMERA = 26;
+        OP_RECORD_AUDIO = 27;
+    }
+    optional AppOpName app_op_name = 2 [default = OP_NONE];
+
+    // The uid's permission mode for accessing the AppOp during this fgs session.
+    enum Mode {
+        MODE_UNKNOWN = 0;
+        MODE_ALLOWED = 1; // Always allowed
+        MODE_IGNORED = 2; // Denied
+        MODE_FOREGROUND = 3; // Allow-while-in-use (or allowed-one-time)
+    }
+    optional Mode app_op_mode = 3;
+
+    // Number of times this AppOp was requested and allowed.
+    optional int32 count_ops_accepted = 4;
+    // Number of times this AppOp was requested but denied.
+    optional int32 count_ops_rejected = 5;
 }
 
 /**
@@ -8189,7 +8234,7 @@
  */
 message CameraActionEvent {
     // Camera session duration
-    optional int64 duration = 1;
+    optional int64 duration_millis = 1;
 
     // Camera API level used
     optional int32 api_level = 2;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 3b0667d..316a018 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -22,6 +22,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -61,6 +62,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * This class describes an {@link AccessibilityService}. The system notifies an
@@ -552,6 +554,13 @@
      */
     private int mHtmlDescriptionRes;
 
+    // Used for html description of accessibility service. The <img> src tag must follow the
+    // prefix rule. e.g. <img src="R.drawable.fileName"/>
+    private static final String IMG_PREFIX = "R.drawable.";
+    private static final String ANCHOR_TAG = "a";
+    private static final List<String> UNSUPPORTED_TAG_LIST = new ArrayList<>(
+            Collections.singletonList(ANCHOR_TAG));
+
     /**
      * Creates a new instance.
      */
@@ -782,12 +791,10 @@
     }
 
     /**
-     * The animated image resource id.
-     * <p>
-     *    <strong>Statically set from
-     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
-     * </p>
+     * Gets the animated image resource id.
+     *
      * @return The animated image resource id.
+     *
      * @hide
      */
     public int getAnimatedImageRes() {
@@ -797,10 +804,12 @@
     /**
      * The animated image drawable.
      * <p>
+     *    Image can not exceed the screen size.
      *    <strong>Statically set from
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
-     * @return The animated image drawable.
+     * @return The animated image drawable, or null if the resource is invalid or the image
+     * exceed the screen size.
      */
     @Nullable
     public Drawable loadAnimatedImage(@NonNull Context context)  {
@@ -808,11 +817,8 @@
             return null;
         }
 
-        final PackageManager packageManager = context.getPackageManager();
-        final String packageName = mComponentName.getPackageName();
-        final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo;
-
-        return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+        return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo,
+                mAnimatedImageRes);
     }
 
     /**
@@ -924,16 +930,17 @@
     }
 
     /**
-     * The localized html description of the accessibility service.
+     * The localized and restricted html description of the accessibility service.
      * <p>
+     *    Filters the <img> tag which do not meet the custom specification and the <a> tag.
      *    <strong>Statically set from
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
-     * @return The localized html description.
+     * @return The localized and restricted html description.
      */
     @Nullable
     public String loadHtmlDescription(@NonNull PackageManager packageManager) {
-        if (mHtmlDescriptionRes == 0) {
+        if (mHtmlDescriptionRes == /* invalid */ 0) {
             return null;
         }
 
@@ -941,7 +948,7 @@
         final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName,
                 mHtmlDescriptionRes, serviceInfo.applicationInfo);
         if (htmlDescription != null) {
-            return htmlDescription.toString().trim();
+            return getFilteredHtmlText(htmlDescription.toString().trim());
         }
         return null;
     }
@@ -1414,4 +1421,103 @@
             return new AccessibilityServiceInfo[size];
         }
     };
+
+    /**
+     * Gets the filtered html string for
+     * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+     * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It filters
+     * the <img> tag which do not meet the custom specification and the <a> tag.
+     *
+     * @param text the target text is html format.
+     * @return the filtered html string.
+     *
+     * @hide
+     */
+    public static @NonNull String getFilteredHtmlText(@NonNull String text) {
+        final String replacementStart = "<invalidtag ";
+        final String replacementEnd = "</invalidtag>";
+
+        for (String tag : UNSUPPORTED_TAG_LIST) {
+            final String regexStart = "(?i)<" + tag + "(\\s+|>)";
+            final String regexEnd = "(?i)</" + tag + "\\s*>";
+            text = Pattern.compile(regexStart).matcher(text).replaceAll(replacementStart);
+            text = Pattern.compile(regexEnd).matcher(text).replaceAll(replacementEnd);
+        }
+
+        final String regexInvalidImgTag = "(?i)<img\\s+(?!src\\s*=\\s*\"(?-i)" + IMG_PREFIX + ")";
+        text = Pattern.compile(regexInvalidImgTag).matcher(text).replaceAll(
+                replacementStart);
+
+        return text;
+    }
+
+    /**
+     * Loads the animated image for
+     * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+     * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It checks the resource
+     * whether to exceed the screen size.
+     *
+     * @param context the current context.
+     * @param applicationInfo the current application.
+     * @param resId the animated image resource id.
+     * @return the animated image which is safe.
+     *
+     * @hide
+     */
+    @Nullable
+    public static Drawable loadSafeAnimatedImage(@NonNull Context context,
+            @NonNull ApplicationInfo applicationInfo, @StringRes int resId) {
+        if (resId == /* invalid */ 0) {
+            return null;
+        }
+
+        final PackageManager packageManager = context.getPackageManager();
+        final String packageName = applicationInfo.packageName;
+        final Drawable bannerDrawable = packageManager.getDrawable(packageName, resId,
+                applicationInfo);
+        if (bannerDrawable == null) {
+            return null;
+        }
+
+        final boolean isImageWidthOverScreenLength =
+                bannerDrawable.getIntrinsicWidth() > getScreenWidthPixels(context);
+        final boolean isImageHeightOverScreenLength =
+                bannerDrawable.getIntrinsicHeight() > getScreenHeightPixels(context);
+
+        return (isImageWidthOverScreenLength || isImageHeightOverScreenLength)
+                ? null
+                : bannerDrawable;
+    }
+
+    /**
+     * Gets the width of the screen.
+     *
+     * @param context the current context.
+     * @return the width of the screen in term of pixels.
+     *
+     * @hide
+     */
+    private static int getScreenWidthPixels(@NonNull Context context) {
+        final Resources resources = context.getResources();
+        final int screenWidthDp = resources.getConfiguration().screenWidthDp;
+
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenWidthDp,
+                resources.getDisplayMetrics()));
+    }
+
+    /**
+     * Gets the height of the screen.
+     *
+     * @param context the current context.
+     * @return the height of the screen in term of pixels.
+     *
+     * @hide
+     */
+    private static int getScreenHeightPixels(@NonNull Context context) {
+        final Resources resources = context.getResources();
+        final int screenHeightDp = resources.getConfiguration().screenHeightDp;
+
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp,
+                resources.getDisplayMetrics()));
+    }
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 6209679..a812f29 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -28,13 +29,19 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Activities of interest to users with accessibility needs may request to be targets of the
@@ -87,6 +94,13 @@
      */
     private final int mHtmlDescriptionRes;
 
+    // Used for html description of accessibility service. The <img> src tag must follow the
+    // prefix rule. e.g. <img src="R.drawable.fileName"/>
+    private static final String IMG_PREFIX = "R.drawable.";
+    private static final String ANCHOR_TAG = "a";
+    private static final List<String> UNSUPPORTED_TAG_LIST = new ArrayList<>(
+            Collections.singletonList(ANCHOR_TAG));
+
     /**
      * Creates a new instance.
      *
@@ -134,7 +148,7 @@
             // Gets animated image
             mAnimatedImageRes = asAttributes.getResourceId(
                     com.android.internal.R.styleable
-                            .AccessibilityShortcutTarget_animatedImageDrawable, 0);
+                            .AccessibilityShortcutTarget_animatedImageDrawable, /* defValue= */ 0);
             // Gets html description
             mHtmlDescriptionRes = asAttributes.getResourceId(
                     com.android.internal.R.styleable.AccessibilityShortcutTarget_htmlDescription,
@@ -192,7 +206,7 @@
     }
 
     /**
-     * The animated image resource id of the accessibility shortcut target.
+     * Gets the animated image resource id.
      *
      * @return The animated image resource id.
      *
@@ -205,7 +219,8 @@
     /**
      * The animated image drawable of the accessibility shortcut target.
      *
-     * @return The animated image drawable.
+     * @return The animated image drawable, or null if the resource is invalid or the image
+     * exceed the screen size.
      */
     @Nullable
     public Drawable loadAnimatedImage(@NonNull Context context) {
@@ -213,21 +228,20 @@
             return null;
         }
 
-        final PackageManager packageManager = context.getPackageManager();
-        final String packageName = mComponentName.getPackageName();
-        final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo;
-
-        return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo);
+        return loadSafeAnimatedImage(context, mActivityInfo.applicationInfo, mAnimatedImageRes);
     }
 
     /**
-     * The localized html description of the accessibility shortcut target.
+     * The localized and restricted html description of the accessibility shortcut target.
+     * It filters the <img> tag which do not meet the custom specification and the <a> tag.
      *
-     * @return The localized html description.
+     * @return The localized and restricted html description.
      */
     @Nullable
     public String loadHtmlDescription(@NonNull PackageManager packageManager) {
-        return loadResourceString(packageManager, mActivityInfo, mHtmlDescriptionRes);
+        final String htmlDescription = loadResourceString(packageManager, mActivityInfo,
+                mHtmlDescriptionRes);
+        return TextUtils.isEmpty(htmlDescription) ? null : getFilteredHtmlText(htmlDescription);
     }
 
     /**
@@ -291,4 +305,103 @@
         stringBuilder.append("]");
         return stringBuilder.toString();
     }
+
+    /**
+     * Gets the filtered html string for
+     * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+     * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It filters
+     * the <img> tag which do not meet the custom specification and the <a> tag.
+     *
+     * @param text the target text is html format.
+     * @return the filtered html string.
+     *
+     * @hide
+     */
+    public static @NonNull String getFilteredHtmlText(@NonNull String text) {
+        final String replacementStart = "<invalidtag ";
+        final String replacementEnd = "</invalidtag>";
+
+        for (String tag : UNSUPPORTED_TAG_LIST) {
+            final String regexStart = "(?i)<" + tag + "(\\s+|>)";
+            final String regexEnd = "(?i)</" + tag + "\\s*>";
+            text = Pattern.compile(regexStart).matcher(text).replaceAll(replacementStart);
+            text = Pattern.compile(regexEnd).matcher(text).replaceAll(replacementEnd);
+        }
+
+        final String regexInvalidImgTag = "(?i)<img\\s+(?!src\\s*=\\s*\"(?-i)" + IMG_PREFIX + ")";
+        text = Pattern.compile(regexInvalidImgTag).matcher(text).replaceAll(
+                replacementStart);
+
+        return text;
+    }
+
+    /**
+     * Loads the animated image for
+     * {@link android.accessibilityservice.AccessibilityServiceInfo} and
+     * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It checks the resource
+     * whether to exceed the screen size.
+     *
+     * @param context the current context.
+     * @param applicationInfo the current application.
+     * @param resId the animated image resource id.
+     * @return the animated image which is safe.
+     *
+     * @hide
+     */
+    @Nullable
+    public static Drawable loadSafeAnimatedImage(@NonNull Context context,
+            @NonNull ApplicationInfo applicationInfo, @StringRes int resId) {
+        if (resId == /* invalid */ 0) {
+            return null;
+        }
+
+        final PackageManager packageManager = context.getPackageManager();
+        final String packageName = applicationInfo.packageName;
+        final Drawable bannerDrawable = packageManager.getDrawable(packageName, resId,
+                applicationInfo);
+        if (bannerDrawable == null) {
+            return null;
+        }
+
+        final boolean isImageWidthOverScreenLength =
+                bannerDrawable.getIntrinsicWidth() > getScreenWidthPixels(context);
+        final boolean isImageHeightOverScreenLength =
+                bannerDrawable.getIntrinsicHeight() > getScreenHeightPixels(context);
+
+        return (isImageWidthOverScreenLength || isImageHeightOverScreenLength)
+                ? null
+                : bannerDrawable;
+    }
+
+    /**
+     * Gets the width of the screen.
+     *
+     * @param context the current context.
+     * @return the width of the screen in term of pixels.
+     *
+     * @hide
+     */
+    private static int getScreenWidthPixels(@NonNull Context context) {
+        final Resources resources = context.getResources();
+        final int screenWidthDp = resources.getConfiguration().screenWidthDp;
+
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenWidthDp,
+                resources.getDisplayMetrics()));
+    }
+
+    /**
+     * Gets the height of the screen.
+     *
+     * @param context the current context.
+     * @return the height of the screen in term of pixels.
+     *
+     * @hide
+     */
+    private static int getScreenHeightPixels(@NonNull Context context) {
+        final Resources resources = context.getResources();
+        final int screenHeightDp = resources.getConfiguration().screenHeightDp;
+
+        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp,
+                resources.getDisplayMetrics()));
+    }
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 82fdb90..b51bbdf 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2012,15 +2012,16 @@
         /** See {@link android.view.Surface.Rotation} */
         @Surface.Rotation
         private int mRotation;
+        /** The size of the snapshot before scaling */
+        private final Point mTaskSize;
         private final Rect mContentInsets;
-        // Whether this snapshot is a down-sampled version of the full resolution, used mainly for
-        // low-ram devices
+        // Whether this snapshot is a down-sampled version of the high resolution snapshot, used
+        // mainly for loading snapshots quickly from disk when user is flinging fast
         private final boolean mIsLowResolution;
         // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to
         // the task having a secure window or having previews disabled
         private final boolean mIsRealSnapshot;
         private final int mWindowingMode;
-        private final float mScale;
         private final int mSystemUiVisibility;
         private final boolean mIsTranslucent;
         // Must be one of the named color spaces, otherwise, always use SRGB color space.
@@ -2028,9 +2029,9 @@
 
         public TaskSnapshot(long id,
                 @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot,
-                @NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets,
-                boolean isLowResolution, float scale, boolean isRealSnapshot, int windowingMode,
-                int systemUiVisibility, boolean isTranslucent) {
+                @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
+                Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot,
+                int windowingMode, int systemUiVisibility, boolean isTranslucent) {
             mId = id;
             mTopActivityComponent = topActivityComponent;
             mSnapshot = snapshot;
@@ -2038,9 +2039,9 @@
                     ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace;
             mOrientation = orientation;
             mRotation = rotation;
+            mTaskSize = new Point(taskSize);
             mContentInsets = new Rect(contentInsets);
             mIsLowResolution = isLowResolution;
-            mScale = scale;
             mIsRealSnapshot = isRealSnapshot;
             mWindowingMode = windowingMode;
             mSystemUiVisibility = systemUiVisibility;
@@ -2057,9 +2058,9 @@
                     : ColorSpace.get(ColorSpace.Named.SRGB);
             mOrientation = source.readInt();
             mRotation = source.readInt();
+            mTaskSize = source.readParcelable(null /* classLoader */);
             mContentInsets = source.readParcelable(null /* classLoader */);
             mIsLowResolution = source.readBoolean();
-            mScale = source.readFloat();
             mIsRealSnapshot = source.readBoolean();
             mWindowingMode = source.readInt();
             mSystemUiVisibility = source.readInt();
@@ -2111,6 +2112,14 @@
         }
 
         /**
+         * @return The size of the task at the point this snapshot was taken.
+         */
+        @UnsupportedAppUsage
+        public Point getTaskSize() {
+            return mTaskSize;
+        }
+
+        /**
          * @return The system/content insets on the snapshot. These can be clipped off in order to
          *         remove any areas behind system bars in the snapshot.
          */
@@ -2159,14 +2168,6 @@
             return mSystemUiVisibility;
         }
 
-        /**
-         * @return The scale this snapshot was taken in.
-         */
-        @UnsupportedAppUsage
-        public float getScale() {
-            return mScale;
-        }
-
         @Override
         public int describeContents() {
             return 0;
@@ -2180,9 +2181,9 @@
             dest.writeInt(mColorSpace.getId());
             dest.writeInt(mOrientation);
             dest.writeInt(mRotation);
+            dest.writeParcelable(mTaskSize, 0);
             dest.writeParcelable(mContentInsets, 0);
             dest.writeBoolean(mIsLowResolution);
-            dest.writeFloat(mScale);
             dest.writeBoolean(mIsRealSnapshot);
             dest.writeInt(mWindowingMode);
             dest.writeInt(mSystemUiVisibility);
@@ -2200,9 +2201,11 @@
                     + " mColorSpace=" + mColorSpace.toString()
                     + " mOrientation=" + mOrientation
                     + " mRotation=" + mRotation
+                    + " mTaskSize=" + mTaskSize.toString()
                     + " mContentInsets=" + mContentInsets.toShortString()
-                    + " mIsLowResolution=" + mIsLowResolution + " mScale=" + mScale
-                    + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode
+                    + " mIsLowResolution=" + mIsLowResolution
+                    + " mIsRealSnapshot=" + mIsRealSnapshot
+                    + " mWindowingMode=" + mWindowingMode
                     + " mSystemUiVisibility=" + mSystemUiVisibility
                     + " mIsTranslucent=" + mIsTranslucent;
         }
@@ -2224,9 +2227,8 @@
             private ColorSpace mColorSpace;
             private int mOrientation;
             private int mRotation;
+            private Point mTaskSize;
             private Rect mContentInsets;
-            private boolean mIsLowResolution;
-            private float mScaleFraction;
             private boolean mIsRealSnapshot;
             private int mWindowingMode;
             private int mSystemUiVisibility;
@@ -2263,28 +2265,19 @@
                 return this;
             }
 
+            /**
+             * Sets the original size of the task
+             */
+            public Builder setTaskSize(Point size) {
+                mTaskSize = size;
+                return this;
+            }
+
             public Builder setContentInsets(Rect contentInsets) {
                 mContentInsets = contentInsets;
                 return this;
             }
 
-            /**
-             * Set to true if this is a low-resolution snapshot stored in *_reduced.jpg.
-             */
-            public Builder setIsLowResolution(boolean isLowResolution) {
-                mIsLowResolution = isLowResolution;
-                return this;
-            }
-
-            public float getScaleFraction() {
-                return mScaleFraction;
-            }
-
-            public Builder setScaleFraction(float scaleFraction) {
-                mScaleFraction = scaleFraction;
-                return this;
-            }
-
             public Builder setIsRealSnapshot(boolean realSnapshot) {
                 mIsRealSnapshot = realSnapshot;
                 return this;
@@ -2322,9 +2315,12 @@
                         mColorSpace,
                         mOrientation,
                         mRotation,
+                        mTaskSize,
                         mContentInsets,
-                        mIsLowResolution,
-                        mScaleFraction,
+                        // When building a TaskSnapshot with the Builder class, isLowResolution
+                        // is always false. Low-res snapshots are only created when loading from
+                        // disk.
+                        false /* isLowResolution */,
                         mIsRealSnapshot,
                         mWindowingMode,
                         mSystemUiVisibility,
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index d48b35b..fb315ad 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -215,8 +215,7 @@
     public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
             boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException {
         try {
-            return getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop,
-                    animate, initialBounds, showRecents);
+            return getService().setTaskWindowingModeSplitScreenPrimary(taskId, toTop);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8f02f15..a53fc35 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -6910,11 +6910,7 @@
      * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
      */
     public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
-        try {
-            return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return unsafeCheckOpRawNoThrow(op, uid, packageName);
     }
 
     /**
@@ -6923,8 +6919,17 @@
      * {@link #MODE_FOREGROUND}.
      */
     public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
+        return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Returns the <em>raw</em> mode associated with the op.
+     * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+     * @hide
+     */
+    public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
         try {
-            return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
+            return mService.checkOperationRaw(op, uid, packageName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 463c8c9..6f0611e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -528,29 +528,6 @@
     boolean unlockUser(int userid, in byte[] token, in byte[] secret,
             in IProgressListener listener);
     void killPackageDependents(in String packageName, int userId);
-    /**
-     * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
-     *
-     * @param dockedBounds The bounds for the docked stack.
-     * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
-     *                             might be different from the stack bounds to allow more
-     *                             flexibility while resizing, or {@code null} if they should be the
-     *                             same as the stack bounds.
-     * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
-     *                                  When resizing, we usually "freeze" the layout of a task. To
-     *                                  achieve that, we also need to "freeze" the insets, which
-     *                                  gets achieved by changing task bounds but not bounds used
-     *                                  to calculate the insets in this transient state
-     * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
-     *                            {@code null} if they should be the same as the stack bounds.
-     * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
-     *                                 stacks.
-     * @throws RemoteException
-     */
-    @UnsupportedAppUsage
-    void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds,
-            in Rect tempDockedTaskInsetBounds,
-            in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
     @UnsupportedAppUsage
     void removeStack(int stackId);
     void makePackageIdle(String packageName, int userId);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 266a06a..7c89263 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -244,8 +244,7 @@
      */
     boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop);
     void moveTaskToStack(int taskId, int stackId, boolean toTop);
-    boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
-            boolean animate, in Rect initialBounds, boolean showRecents);
+    boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop);
     /**
      * Removes stacks in the input windowing modes from the system if they are of activity type
      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6dea1c6..ccd8199 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -182,6 +182,16 @@
     public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
 
     /**
+     * A bundle extra that contains whether or not an app has finished restoring a widget.
+     * <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its
+     * widgets followed by calling {@link #updateAppWidget} to update the views.
+     *
+     * @see #updateAppWidgetOptions(int, Bundle)
+     */
+    public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
+
+
+    /**
      * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
      */
     public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java
index ab91edf..a5d2198 100644
--- a/core/java/android/appwidget/AppWidgetProvider.java
+++ b/core/java/android/appwidget/AppWidgetProvider.java
@@ -200,6 +200,9 @@
      * provider can immediately generate new RemoteViews suitable for its newly-restored set
      * of instances.
      *
+     * <p>In addition, you should set {@link AppWidgetManager#OPTION_APPWIDGET_RESTORE_COMPLETED}
+     * to true indicate if a widget has been restored successfully from the provider's side.
+     *
      * {@more}
      *
      * @param context
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 9e40f46..9da0f20 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -54,7 +54,6 @@
 
     private final int mHash;
 
-    @UnsupportedAppUsage
     public ResourcesKey(@Nullable String resDir,
                         @Nullable String[] splitResDirs,
                         @Nullable String[] overlayDirs,
@@ -85,6 +84,18 @@
         mHash = hash;
     }
 
+    @UnsupportedAppUsage
+    public ResourcesKey(@Nullable String resDir,
+            @Nullable String[] splitResDirs,
+            @Nullable String[] overlayDirs,
+            @Nullable String[] libDirs,
+            int displayId,
+            @Nullable Configuration overrideConfig,
+            @Nullable CompatibilityInfo compatInfo) {
+        this(resDir, splitResDirs, overlayDirs, libDirs, displayId, overrideConfig, compatInfo,
+                null);
+    }
+
     public boolean hasOverrideConfiguration() {
         return !Configuration.EMPTY.equals(mOverrideConfiguration);
     }
diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java
index 0bd9f19..d730129 100644
--- a/core/java/android/debug/AdbManagerInternal.java
+++ b/core/java/android/debug/AdbManagerInternal.java
@@ -53,4 +53,14 @@
      * Returns the file that contains all of the ADB keys and their last used time.
      */
     public abstract File getAdbTempKeysFile();
+
+    /**
+     * Starts adbd for a transport.
+     */
+    public abstract void startAdbdForTransport(byte transportType);
+
+    /**
+     * Stops adbd for a transport.
+     */
+    public abstract void stopAdbdForTransport(byte transportType);
 }
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index 17e0456..fcdefac 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -23,16 +23,13 @@
 import android.annotation.TestApi;
 import android.app.Service;
 import android.app.slice.Slice;
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.PixelFormat;
-import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Display;
 import android.view.SurfaceControl;
@@ -76,35 +73,41 @@
             return;
         }
 
-        final DisplayManager displayManager = getSystemService(DisplayManager.class);
-        final Display targetDisplay = displayManager.getDisplay(displayId);
-        if (targetDisplay == null) {
-            sendResult(callback, /*surface*/ null);
-            return;
-        }
-        final Context displayContext = createDisplayContext(targetDisplay);
-
-        final SurfaceControlViewHost host = new SurfaceControlViewHost(displayContext,
-                displayContext.getDisplay(), hostInputToken);
-        final SurfaceControl surface = host.getSurfacePackage().getSurfaceControl();
-
-        final View suggestionView = onRenderSuggestion(presentation, width, height);
-
-        final InlineSuggestionRoot suggestionRoot = new InlineSuggestionRoot(this, callback);
-        suggestionRoot.addView(suggestionView);
-        suggestionRoot.setOnClickListener((v) -> {
-            try {
-                callback.onAutofill();
-            } catch (RemoteException e) {
-                Log.w(TAG, "RemoteException calling onAutofill()");
+        // When we create the UI it should be for the IME display
+        updateDisplay(displayId);
+        try {
+            final View suggestionView = onRenderSuggestion(presentation, width, height);
+            if (suggestionView == null) {
+                try {
+                    callback.onError();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Null suggestion view returned by renderer");
+                }
+                return;
             }
-        });
 
-        WindowManager.LayoutParams lp =
-                new WindowManager.LayoutParams(width, height,
-                        WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
-        host.addView(suggestionRoot, lp);
-        sendResult(callback, surface);
+            final InlineSuggestionRoot suggestionRoot = new InlineSuggestionRoot(this, callback);
+            suggestionRoot.addView(suggestionView);
+            WindowManager.LayoutParams lp =
+                    new WindowManager.LayoutParams(width, height,
+                            WindowManager.LayoutParams.TYPE_APPLICATION, 0,
+                            PixelFormat.TRANSPARENT);
+
+            final SurfaceControlViewHost host = new SurfaceControlViewHost(this, getDisplay(),
+                    hostInputToken);
+            host.addView(suggestionRoot, lp);
+            suggestionRoot.setOnClickListener((v) -> {
+                try {
+                    callback.onAutofill();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException calling onAutofill()");
+                }
+            });
+
+            sendResult(callback, host.getSurfacePackage().getSurfaceControl());
+        } finally {
+            updateDisplay(Display.DEFAULT_DISPLAY);
+        }
     }
 
     private void sendResult(@NonNull IInlineSuggestionUiCallback callback,
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index 2d1d0ed..0cffe71 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -394,6 +394,11 @@
             return this;
         }
 
+        /**
+         * @param deviceType the device type for the {@link Control}. Setting an invalid value not
+         *                   in {@link DeviceTypes} will set it to {@link DeviceTypes#TYPE_UNKNOWN}.
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
             if (!DeviceTypes.validDeviceType(deviceType)) {
@@ -416,6 +421,10 @@
             return this;
         }
 
+        /**
+         * @param subtitle the user facing subtitle for the {@link Control}
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setSubtitle(@NonNull CharSequence subtitle) {
             Preconditions.checkNotNull(subtitle);
@@ -423,12 +432,22 @@
             return this;
         }
 
+        /**
+         * @param structure the user facing name of the structure for the {@link Control}.
+         *                  {@code null} indicates that it's not associated with any structure.
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setStructure(@Nullable CharSequence structure) {
             mStructure = structure;
             return this;
         }
 
+        /**
+         * @param zone the user facing name of the zone for the {@link Control}. {@code null}
+         *             indicates that it's not associated with any zone.
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setZone(@Nullable CharSequence zone) {
             mZone = zone;
@@ -446,12 +465,20 @@
             return this;
         }
 
+        /**
+         * @param customIcon an {@link Icon} to override the one determined by the device type.
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setCustomIcon(@Nullable Icon customIcon) {
             mCustomIcon = customIcon;
             return this;
         }
 
+        /**
+         * @param customColor a list of colors to override the ones determined by the device type.
+         * @return {@code this}
+         */
         @NonNull
         public StatelessBuilder setCustomColor(@Nullable ColorStateList customColor) {
             mCustomColor = customColor;
@@ -459,7 +486,7 @@
         }
 
         /**
-         * Build a {@link Control}
+         * Build a stateless {@link Control}
          * @return a valid {@link Control}
          */
         @NonNull
@@ -482,7 +509,7 @@
     /**
      * Builder class for {@link Control}.
      *
-     * This class facilitates the creation of {@link Control}.
+     * This class facilitates the creation of {@link Control} with an associated state.
      * It provides the following defaults for non-optional parameters:
      * <ul>
      *     <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN}
@@ -551,6 +578,11 @@
             return this;
         }
 
+        /**
+         * @param deviceType the device type for the {@link Control}. Setting an invalid value not
+         *                   in {@link DeviceTypes} will set it to {@link DeviceTypes#TYPE_UNKNOWN}.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
             if (!DeviceTypes.validDeviceType(deviceType)) {
@@ -573,6 +605,10 @@
             return this;
         }
 
+        /**
+         * @param subtitle the user facing subtitle for the {@link Control}
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setSubtitle(@NonNull CharSequence subtitle) {
             Preconditions.checkNotNull(subtitle);
@@ -580,12 +616,22 @@
             return this;
         }
 
+        /**
+         * @param structure the user facing name of the structure for the {@link Control}.
+         *                  {@code null} indicates that it's not associated with any structure.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setStructure(@Nullable CharSequence structure) {
             mStructure = structure;
             return this;
         }
 
+        /**
+         * @param zone the user facing name of the zone for the {@link Control}. {@code null}
+         *             indicates that it's not associated with any zone.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setZone(@Nullable CharSequence zone) {
             mZone = zone;
@@ -603,18 +649,31 @@
             return this;
         }
 
+        /**
+         * @param customIcon an {@link Icon} to override the one determined by the device type.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setCustomIcon(@Nullable Icon customIcon) {
             mCustomIcon = customIcon;
             return this;
         }
 
+        /**
+         * @param customColor a list of colors to override the ones determined by the device type.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setCustomColor(@Nullable ColorStateList customColor) {
             mCustomColor = customColor;
             return this;
         }
 
+        /**
+         * @param status the status of the {@link Control}. Setting an invalid value not in
+         *               {@link Control} will set it to {@link Control#STATUS_UNKNOWN}.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setStatus(@Status int status) {
             if (status < 0 || status >= NUM_STATUS) {
@@ -626,6 +685,10 @@
             return this;
         }
 
+        /**
+         * @param controlTemplate a template for the {@link Control}
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setControlTemplate(@NonNull ControlTemplate controlTemplate) {
             Preconditions.checkNotNull(controlTemplate);
@@ -633,6 +696,10 @@
             return this;
         }
 
+        /**
+         * @param statusText a user facing text representing the status of the {@link Control}.
+         * @return {@code this}
+         */
         @NonNull
         public StatefulBuilder setStatusText(@NonNull CharSequence statusText) {
             Preconditions.checkNotNull(statusText);
@@ -640,6 +707,10 @@
             return this;
         }
 
+        /**
+         * Build a stateless {@link Control}
+         * @return a valid {@link Control}
+         */
         @NonNull
         public Control build() {
             return new Control(mControlId,
diff --git a/core/java/android/service/controls/DeviceTypes.java b/core/java/android/service/controls/DeviceTypes.java
index 8dbb9cf..6594d2c 100644
--- a/core/java/android/service/controls/DeviceTypes.java
+++ b/core/java/android/service/controls/DeviceTypes.java
@@ -21,6 +21,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+/**
+ * Device types for {@link Control}.
+ */
 public class DeviceTypes {
 
     // Update this when adding new concrete types. Does not count TYPE_UNKNOWN
diff --git a/core/java/android/service/controls/actions/BooleanAction.java b/core/java/android/service/controls/actions/BooleanAction.java
index 0259335..b794ead 100644
--- a/core/java/android/service/controls/actions/BooleanAction.java
+++ b/core/java/android/service/controls/actions/BooleanAction.java
@@ -19,10 +19,15 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
+import android.service.controls.Control;
+import android.service.controls.templates.ToggleRangeTemplate;
 import android.service.controls.templates.ToggleTemplate;
 
 /**
- * Action sent by a {@link ToggleTemplate}
+ * Action sent by user toggling a {@link Control} between checked/unchecked.
+ *
+ * This action is available when the {@link Control} was constructed with either a
+ * {@link ToggleTemplate} or a {@link ToggleRangeTemplate}.
  */
 public final class BooleanAction extends ControlAction {
 
@@ -40,8 +45,8 @@
     }
 
     /**
-     * @param templateId the identifier of the {@link ToggleTemplate} that originated this action.
-     * @param newState new value for the state displayed by the {@link ToggleTemplate}.
+     * @param templateId the identifier of the template that originated this action.
+     * @param newState new value for the state displayed by the template.
      * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
      *                       null is sent when no authentication is needed or has not been
      *                       requested.
@@ -64,8 +69,7 @@
     /**
      * The new state set for the button in the corresponding {@link ToggleTemplate}.
      *
-     * @return {@code true} if the button was toggled from an {@code off} state to an {@code on}
-     *         state.
+     * @return {@code true} if the button was toggled from unchecked to checked.
      */
     public boolean getNewState() {
         return mNewState;
diff --git a/core/java/android/service/controls/actions/CommandAction.java b/core/java/android/service/controls/actions/CommandAction.java
index 84d6080..a560fa4 100644
--- a/core/java/android/service/controls/actions/CommandAction.java
+++ b/core/java/android/service/controls/actions/CommandAction.java
@@ -19,15 +19,32 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
+import android.service.controls.Control;
+import android.service.controls.templates.StatelessTemplate;
 
+/**
+ * A simple {@link ControlAction} indicating that the user has interacted with a {@link Control}
+ * created using a {@link StatelessTemplate}.
+ */
 public final class CommandAction extends ControlAction {
 
     private static final @ActionType int TYPE = TYPE_COMMAND;
 
+    /**
+     * @param templateId the identifier of the {@link StatelessTemplate} that originated this
+     *                   action.
+     * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+     *                       null is sent when no authentication is needed or has not been
+     *                       requested.
+     */
     public CommandAction(@NonNull String templateId, @Nullable String challengeValue) {
         super(templateId, challengeValue);
     }
 
+    /**
+     * @param templateId the identifier of the {@link StatelessTemplate} that originated this
+     *                   action.
+     */
     public CommandAction(@NonNull String templateId) {
         this(templateId, null);
     }
@@ -40,6 +57,9 @@
         super(b);
     }
 
+    /**
+     * @return {@link ControlAction#TYPE_COMMAND}
+     */
     @Override
     public int getActionType() {
         return TYPE;
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 4141da8..45e63d7 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
+import android.service.controls.Control;
 import android.service.controls.IControlsActionCallback;
 import android.service.controls.templates.ControlTemplate;
 import android.util.Log;
@@ -31,7 +32,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * An abstract action that is executed from a {@link ControlTemplate}.
+ * An abstract action indicating a user interaction with a {@link Control}.
  *
  * The action may have a value to authenticate the input, when the provider has requested it to
  * complete the action.
@@ -58,6 +59,9 @@
     })
     public @interface ActionType {};
 
+    /**
+     * Object returned when there is an unparcelling error.
+     */
     public static final @NonNull ControlAction ERROR_ACTION = new ControlAction() {
         @Override
         public int getActionType() {
@@ -65,6 +69,9 @@
         }
     };
 
+    /**
+     * The identifier of {@link #ERROR_ACTION}
+     */
     public static final @ActionType int TYPE_ERROR = -1;
 
     /**
@@ -77,10 +84,19 @@
      */
     public static final @ActionType int TYPE_FLOAT = 2;
 
+    /**
+     * The identifier of {@link MultiFloatAction}.
+     */
     public static final @ActionType int TYPE_MULTI_FLOAT = 3;
 
+    /**
+     * The identifier of {@link ModeAction}.
+     */
     public static final @ActionType int TYPE_MODE = 4;
 
+    /**
+     * The identifier of {@link CommandAction}.
+     */
     public static final @ActionType int TYPE_COMMAND = 5;
 
 
diff --git a/core/java/android/service/controls/actions/ModeAction.java b/core/java/android/service/controls/actions/ModeAction.java
index ca40974d..c0e24ad 100644
--- a/core/java/android/service/controls/actions/ModeAction.java
+++ b/core/java/android/service/controls/actions/ModeAction.java
@@ -19,7 +19,15 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
+import android.service.controls.Control;
+import android.service.controls.templates.TemperatureControlTemplate;
 
+/**
+ * Action sent by the user to indicate a change of mode.
+ *
+ * This action is available when the {@link Control} was created with a
+ * {@link TemperatureControlTemplate}.
+ */
 public final class ModeAction extends ControlAction {
 
     private static final @ActionType int TYPE = TYPE_MODE;
@@ -27,16 +35,32 @@
 
     private final int mNewMode;
 
+    /**
+     * @return {@link ControlAction#TYPE_MODE}.
+     */
     @Override
     public int getActionType() {
         return TYPE;
     }
 
+    /**
+     * @param templateId the identifier of the {@link TemperatureControlTemplate} that originated
+     *                   this action.
+     * @param newMode new value for the mode.
+     * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+     *                       null is sent when no authentication is needed or has not been
+     *                       requested.
+     */
     public ModeAction(@NonNull String templateId, int newMode, @Nullable String challengeValue) {
         super(templateId, challengeValue);
         mNewMode = newMode;
     }
 
+    /**
+     * @param templateId the identifier of the {@link TemperatureControlTemplate} that originated
+     *                   this action.
+     * @param newMode new value for the mode.
+     */
     public ModeAction(@NonNull String templateId, int newMode) {
         this(templateId, newMode, null);
     }
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index a5156e3..30efd80 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -57,6 +57,9 @@
         }
     };
 
+    /**
+     * Object returned when there is an unparcelling error.
+     */
     public static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") {
         @Override
         public int getTemplateType() {
@@ -80,6 +83,9 @@
     })
     public @interface TemplateType {}
 
+    /**
+     * Type identifier of {@link #ERROR_TEMPLATE}.
+     */
     public static final @TemplateType int TYPE_ERROR = -1;
 
     /**
@@ -102,10 +108,19 @@
      */
     public static final @TemplateType int TYPE_THUMBNAIL = 3;
 
+    /**
+     * Type identifier of {@link ToggleRangeTemplate}.
+     */
     public static final @TemplateType int TYPE_TOGGLE_RANGE = 6;
 
+    /**
+     * Type identifier of {@link TemperatureControlTemplate}.
+     */
     public static final @TemplateType int TYPE_TEMPERATURE = 7;
 
+    /**
+     * Type identifier of {@link StatelessTemplate}.
+     */
     public static final @TemplateType int TYPE_STATELESS = 8;
 
     private @NonNull final String mTemplateId;
diff --git a/core/java/android/service/controls/templates/RangeTemplate.java b/core/java/android/service/controls/templates/RangeTemplate.java
index fe0d167..0d977d3 100644
--- a/core/java/android/service/controls/templates/RangeTemplate.java
+++ b/core/java/android/service/controls/templates/RangeTemplate.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Bundle;
-import android.os.Parcel;
 import android.service.controls.Control;
 import android.service.controls.actions.FloatAction;
 
@@ -85,7 +84,7 @@
     }
 
     /**
-     * Construct a new {@link RangeTemplate} from a {@link Parcel}.
+     * Construct a new {@link RangeTemplate} from a {@link Bundle}.
      *
      * @throws IllegalArgumentException if the parameters passed do not make a valid range
      * @see RangeTemplate#RangeTemplate(String, float, float, float, float, CharSequence)
diff --git a/core/java/android/service/controls/templates/StatelessTemplate.java b/core/java/android/service/controls/templates/StatelessTemplate.java
index 3f98bea..c052412 100644
--- a/core/java/android/service/controls/templates/StatelessTemplate.java
+++ b/core/java/android/service/controls/templates/StatelessTemplate.java
@@ -18,22 +18,36 @@
 
 import android.annotation.NonNull;
 import android.os.Bundle;
+import android.service.controls.Control;
+import android.service.controls.actions.CommandAction;
 
+/**
+ * A template for a {@link Control} which has no state.
+ *
+ * @see CommandAction
+ */
 public final class StatelessTemplate extends ControlTemplate {
 
+    /**
+     * @return {@link ControlTemplate#TYPE_STATELESS}
+     */
     @Override
     public int getTemplateType() {
         return TYPE_STATELESS;
     }
 
     /**
-     * @param b
+     * Construct a new {@link StatelessTemplate} from a {@link Bundle}
      * @hide
      */
     StatelessTemplate(@NonNull Bundle b) {
         super(b);
     }
 
+    /**
+     * Construct a new {@link StatelessTemplate}
+     * @param templateId the identifier for this template
+     */
     public StatelessTemplate(@NonNull String templateId) {
         super(templateId);
     }
diff --git a/core/java/android/service/controls/templates/TemperatureControlTemplate.java b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
index 9d8dca62..0818c7e 100644
--- a/core/java/android/service/controls/templates/TemperatureControlTemplate.java
+++ b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.os.Bundle;
+import android.service.controls.Control;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -26,6 +27,13 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+/**
+ * A template for a temperature related {@link Control} that supports multiple modes.
+ *
+ * Both the current mode and the active mode for the control can be specified. The combination of
+ * the {@link Control#getDeviceType} and the current and active mode will determine colors and
+ * transitions for the UI element.
+ */
 public final class TemperatureControlTemplate extends ControlTemplate {
 
     private static final String TAG = "ThermostatTemplate";
@@ -51,6 +59,7 @@
     public @interface Mode {}
 
     private static final int NUM_MODES = 6;
+
     public static final @Mode int MODE_UNKNOWN = 0;
 
     public static final @Mode int MODE_OFF = 1;
@@ -102,6 +111,18 @@
     private final @Mode int mCurrentActiveMode;
     private final @ModeFlag int mModes;
 
+    /**
+     * Construct a new {@link TemperatureControlTemplate}.
+     *
+     * The current and active mode have to be among the ones supported by the flags.
+     *
+     * @param templateId the identifier for this template object
+     * @param controlTemplate a template to use for interaction with the user
+     * @param currentMode the current mode for the {@link Control}
+     * @param currentActiveMode the current active mode for the {@link Control}
+     * @param modesFlag a flag representing the available modes for the {@link Control}
+     * @throws IllegalArgumentException if the parameters passed do not make a valid template.
+     */
     public TemperatureControlTemplate(@NonNull String templateId,
             @NonNull ControlTemplate controlTemplate,
             @Mode int currentMode,
@@ -179,6 +200,9 @@
         return mModes;
     }
 
+    /**
+     * @return {@link ControlTemplate#TYPE_TEMPERATURE}
+     */
     @Override
     public int getTemplateType() {
         return TYPE;
diff --git a/core/java/android/service/controls/templates/ToggleRangeTemplate.java b/core/java/android/service/controls/templates/ToggleRangeTemplate.java
index af43b94..cd6a2fc 100644
--- a/core/java/android/service/controls/templates/ToggleRangeTemplate.java
+++ b/core/java/android/service/controls/templates/ToggleRangeTemplate.java
@@ -18,9 +18,16 @@
 
 import android.annotation.NonNull;
 import android.os.Bundle;
+import android.service.controls.Control;
 
 import com.android.internal.util.Preconditions;
 
+/**
+ * A template for a {@link Control} supporting toggling and a range.
+ *
+ * @see ToggleTemplate
+ * @see RangeTemplate
+ */
 public final class ToggleRangeTemplate extends ControlTemplate {
 
     private static final @TemplateType int TYPE = TYPE_TOGGLE_RANGE;
@@ -40,6 +47,12 @@
         mRangeTemplate = new RangeTemplate(b.getBundle(KEY_RANGE));
     }
 
+    /**
+     * Constructs a new {@link ToggleRangeTemplate}.
+     * @param templateId the identifier for this template.
+     * @param button a {@link ControlButton} to use for the toggle interface
+     * @param range a {@link RangeTemplate} to use for the range interface
+     */
     public ToggleRangeTemplate(@NonNull String templateId,
             @NonNull ControlButton button,
             @NonNull RangeTemplate range) {
@@ -50,6 +63,14 @@
         mRangeTemplate = range;
     }
 
+    /**
+     * Constructs a new {@link ToggleRangeTemplate}.
+     * @param templateId the identifier for this template.
+     * @param checked true if the toggle should be rendered as active.
+     * @param actionDescription action description for the button.
+     * @param range  {@link RangeTemplate} to use for the range interface
+     * @see ControlButton
+     */
     public ToggleRangeTemplate(@NonNull String templateId,
             boolean checked,
             @NonNull CharSequence actionDescription,
@@ -86,6 +107,9 @@
         return mControlButton.getActionDescription();
     }
 
+    /**
+     * @return {@link ControlTemplate#TYPE_TOGGLE_RANGE}
+     */
     @Override
     public int getTemplateType() {
         return TYPE;
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 28f4929..002d4b8 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -883,7 +883,7 @@
      * </p>
      */
     public void onWakeUp() {
-        mActivity.finishAndRemoveTask();
+        finish();
     }
 
     /** {@inheritDoc} */
@@ -904,13 +904,14 @@
     public final void finish() {
         if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished);
 
-        if (mActivity == null) {
+        if (mActivity != null) {
+            if (!mActivity.isFinishing()) {
+                // In case the activity is not finished yet, do it now.
+                mActivity.finishAndRemoveTask();
+                return;
+            }
+        } else if (!mWindowless) {
             Slog.w(TAG, "Finish was called before the dream was attached.");
-        } else if (!mActivity.isFinishing()) {
-            // In case the activity is not finished yet, do it now. This can happen if someone calls
-            // finish() directly, without going through wakeUp().
-            mActivity.finishAndRemoveTask();
-            return;
         }
 
         if (!mFinished) {
@@ -1010,7 +1011,7 @@
      * @param started A callback that will be invoked once onDreamingStarted has completed.
      */
     private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
-        if (mActivity != null) {
+        if (mDreamToken != null) {
             Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
                     + " already attached");
             return;
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
new file mode 100644
index 0000000..2e94be5
--- /dev/null
+++ b/core/java/android/service/notification/OWNERS
@@ -0,0 +1,4 @@
+juliacr@google.com
+beverlyt@google.com
+dsandler@android.com
+pixel@google.com
\ No newline at end of file
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 7b24ba9..9a555c16 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -32,7 +32,7 @@
  * <p>
  * This API is not as convenient or type safe as the standard protobuf
  * classes. If possible, the best recommended library is to use protobuf lite.
- * However, in environements (such as the Android platform itself), a
+ * However, in environments (such as the Android platform itself), a
  * more memory efficient version is necessary.
  *
  * <p>Each write method takes an ID code from the protoc generated classes
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 530dffb..a60a5cc 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -67,11 +67,6 @@
     void setAnimationTargetsBehindSystemBars(boolean behindSystemBars);
 
     /**
-     * Informs the system that the primary split-screen stack should be minimized.
-     */
-    void setSplitScreenMinimized(boolean minimized);
-
-    /**
      * Hides the current input method if one is showing.
      */
     void hideCurrentInputMethod();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1730347..73601d9 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -444,8 +444,7 @@
     WindowContentFrameStats getWindowContentFrameStats(IBinder token);
 
     /**
-     * @return the dock side the current docked stack is at; must be one of the
-     *         WindowManagerGlobal.DOCKED_* values
+     * This is a no-op.
      */
     @UnsupportedAppUsage
     int getDockedStackSide();
@@ -457,27 +456,11 @@
     void setDockedStackDividerTouchRegion(in Rect touchableRegion);
 
     /**
-     * Registers a listener that will be called when the dock divider changes its visibility or when
-     * the docked stack gets added/removed.
-     */
-    @UnsupportedAppUsage
-    void registerDockedStackListener(IDockedStackListener listener);
-
-    /**
      * Registers a listener that will be called when the pinned stack state changes.
      */
     void registerPinnedStackListener(int displayId, IPinnedStackListener listener);
 
     /**
-     * Updates the dim layer used while resizing.
-     *
-     * @param visible Whether the dim layer should be visible.
-     * @param targetWindowingMode The windowing mode of the stack the dim layer should be placed on.
-     * @param alpha The translucency of the dim layer, between 0 and 1.
-     */
-    void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha);
-
-    /**
      * Requests Keyboard Shortcuts from the displayed window.
      *
      * @param receiver The receiver to deliver the results to.
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 5f9c480..cb9e746 100644
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -233,6 +233,21 @@
         return mSeq;
     }
 
+    /**
+     * Gets the ID of this event. This is generated when an event is created and preserved until its
+     * last stage. It won't change just because the event crosses process boundary, but should
+     * change when making a copy with modifications.
+     * <p>
+     * To avoid exposing app usage to other processes this ID is generated from a CSPRNG. Therefore
+     * there isn't 100% guarantee on the uniqueness of this ID, though the chance of ID collisions
+     * is considerably low. The rule of thumb is not to rely on the uniqueness for production logic,
+     * but a good source for tracking an event (e.g. logging and profiling).
+     *
+     * @return The ID of this event.
+     * @hide
+     */
+    public abstract int getId();
+
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 235f5e1..e249c77 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1265,6 +1265,7 @@
 
     private KeyEvent mNext;
 
+    private int mId;
     @UnsupportedAppUsage
     private int mDeviceId;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -1350,9 +1351,9 @@
 
     private static native String nativeKeyCodeToString(int keyCode);
     private static native int nativeKeyCodeFromString(String keyCode);
+    private static native int nativeNextId();
 
-    private KeyEvent() {
-    }
+    private KeyEvent() {}
 
     /**
      * Create a new key event.
@@ -1362,6 +1363,7 @@
      * @param code The key code.
      */
     public KeyEvent(int action, int code) {
+        mId = nativeNextId();
         mAction = action;
         mKeyCode = code;
         mRepeatCount = 0;
@@ -1383,6 +1385,7 @@
      */
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat) {
+        mId = nativeNextId();
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
@@ -1407,6 +1410,7 @@
      */
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState) {
+        mId = nativeNextId();
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
@@ -1435,6 +1439,7 @@
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState,
                     int deviceId, int scancode) {
+        mId = nativeNextId();
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
@@ -1465,6 +1470,7 @@
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState,
                     int deviceId, int scancode, int flags) {
+        mId = nativeNextId();
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
@@ -1497,6 +1503,7 @@
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState,
                     int deviceId, int scancode, int flags, int source) {
+        mId = nativeNextId();
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
@@ -1523,6 +1530,7 @@
      * @param flags The flags for this key event
      */
     public KeyEvent(long time, String characters, int deviceId, int flags) {
+        mId = nativeNextId();
         mDownTime = time;
         mEventTime = time;
         mCharacters = characters;
@@ -1539,6 +1547,7 @@
      * Make an exact copy of an existing key event.
      */
     public KeyEvent(KeyEvent origEvent) {
+        mId = origEvent.mId;
         mDownTime = origEvent.mDownTime;
         mEventTime = origEvent.mEventTime;
         mAction = origEvent.mAction;
@@ -1567,6 +1576,7 @@
      */
     @Deprecated
     public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
+        mId = nativeNextId();  // Not an exact copy so assign a new ID.
         mDownTime = origEvent.mDownTime;
         mEventTime = eventTime;
         mAction = origEvent.mAction;
@@ -1598,15 +1608,16 @@
     }
 
     /**
-     * Obtains a (potentially recycled) key event.
+     * Obtains a (potentially recycled) key event. Used by native code to create a Java object.
      *
      * @hide
      */
-    public static KeyEvent obtain(long downTime, long eventTime, int action,
+    public static KeyEvent obtain(int id, long downTime, long eventTime, int action,
             int code, int repeat, int metaState,
             int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac,
             String characters) {
         KeyEvent ev = obtain();
+        ev.mId = id;
         ev.mDownTime = downTime;
         ev.mEventTime = eventTime;
         ev.mAction = action;
@@ -1628,12 +1639,24 @@
      *
      * @hide
      */
+    public static KeyEvent obtain(long downTime, long eventTime, int action,
+            int code, int repeat, int metaState,
+            int deviceId, int scanCode, int flags, int source, int displayId, String characters) {
+        return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState,
+                deviceId, scanCode, flags, source, displayId, null /* hmac */, characters);
+    }
+
+    /**
+     * Obtains a (potentially recycled) key event.
+     *
+     * @hide
+     */
     @UnsupportedAppUsage
     public static KeyEvent obtain(long downTime, long eventTime, int action,
             int code, int repeat, int metaState,
             int deviceId, int scancode, int flags, int source, String characters) {
         return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode,
-                flags, source, INVALID_DISPLAY, null /* hmac */, characters);
+                flags, source, INVALID_DISPLAY, characters);
     }
 
     /**
@@ -1645,6 +1668,7 @@
      */
     public static KeyEvent obtain(KeyEvent other) {
         KeyEvent ev = obtain();
+        ev.mId = other.mId;
         ev.mDownTime = other.mDownTime;
         ev.mEventTime = other.mEventTime;
         ev.mAction = other.mAction;
@@ -1695,6 +1719,12 @@
         // Do nothing.
     }
 
+    /** @hide */
+    @Override
+    public int getId() {
+        return mId;
+    }
+
     /**
      * Create a new key event that is the same as the given one, but whose
      * event time and repeat count are replaced with the given value.
@@ -1723,6 +1753,7 @@
     public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
             int newRepeat, int newFlags) {
         KeyEvent ret = new KeyEvent(event);
+        ret.mId = nativeNextId();  // Not an exact copy so assign a new ID.
         ret.mEventTime = eventTime;
         ret.mRepeatCount = newRepeat;
         ret.mFlags = newFlags;
@@ -1736,6 +1767,7 @@
      * @param action The new action code of the event.
      */
     private KeyEvent(KeyEvent origEvent, int action) {
+        mId = nativeNextId();  // Not an exact copy so assign a new ID.
         mDownTime = origEvent.mDownTime;
         mEventTime = origEvent.mEventTime;
         mAction = action;
@@ -1772,6 +1804,7 @@
      */
     public static KeyEvent changeFlags(KeyEvent event, int flags) {
         event = new KeyEvent(event);
+        event.mId = nativeNextId();  // Not an exact copy so assign a new ID.
         event.mFlags = flags;
         return event;
     }
@@ -3095,6 +3128,7 @@
     }
 
     private KeyEvent(Parcel in) {
+        mId = in.readInt();
         mDeviceId = in.readInt();
         mSource = in.readInt();
         mDisplayId = in.readInt();
@@ -3114,6 +3148,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(PARCEL_TOKEN_KEY_EVENT);
 
+        out.writeInt(mId);
         out.writeInt(mDeviceId);
         out.writeInt(mSource);
         out.writeInt(mDisplayId);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0068476..19eff72 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1550,6 +1550,8 @@
     private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
             boolean keepHistory);
     @CriticalNative
+    private static native int nativeGetId(long nativePtr);
+    @CriticalNative
     private static native int nativeGetDeviceId(long nativePtr);
     @CriticalNative
     private static native int nativeGetSource(long nativePtr);
@@ -2024,6 +2026,12 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public int getId() {
+        return nativeGetId(mNativePtr);
+    }
+
     /** {@inheritDoc} */
     @Override
     public final int getDeviceId() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 11ab572..15d18d1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -29794,7 +29794,7 @@
 
         // accessibility
         CharSequence contentDescription = getContentDescription();
-        stream.addProperty("accessibility:contentDescription",
+        stream.addUserProperty("accessibility:contentDescription",
                 contentDescription == null ? "" : contentDescription.toString());
         stream.addProperty("accessibility:labelFor", getLabelFor());
         stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility());
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 2f44fe0..8a5be75 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1209,6 +1209,7 @@
         ByteArrayOutputStream baOut = new ByteArrayOutputStream();
 
         final ViewHierarchyEncoder encoder = new ViewHierarchyEncoder(baOut);
+        encoder.setUserPropertiesEnabled(false);
         encoder.addProperty("window:left", view.mAttachInfo.mWindowLeft);
         encoder.addProperty("window:top", view.mAttachInfo.mWindowTop);
         view.encode(encoder);
diff --git a/core/java/android/view/ViewHierarchyEncoder.java b/core/java/android/view/ViewHierarchyEncoder.java
index b0e0524..ace05a6 100644
--- a/core/java/android/view/ViewHierarchyEncoder.java
+++ b/core/java/android/view/ViewHierarchyEncoder.java
@@ -66,10 +66,16 @@
     private short mPropertyId = 1;
     private Charset mCharset = Charset.forName("utf-8");
 
+    private boolean mUserPropertiesEnabled = true;
+
     public ViewHierarchyEncoder(@NonNull ByteArrayOutputStream stream) {
         mStream = new DataOutputStream(stream);
     }
 
+    public void setUserPropertiesEnabled(boolean enabled) {
+        mUserPropertiesEnabled = enabled;
+    }
+
     public void beginObject(@NonNull Object o) {
         startPropertyMap();
         addProperty("meta:__name__", o.getClass().getName());
@@ -121,6 +127,17 @@
     }
 
     /**
+     * Encodes a user defined property if they are allowed to be encoded
+     *
+     * @see #setUserPropertiesEnabled(boolean)
+     */
+    public void addUserProperty(@NonNull String name, @Nullable String s) {
+        if (mUserPropertiesEnabled) {
+            addProperty(name, s);
+        }
+    }
+
+    /**
      * Writes the given name as the property name, and leaves it to the callee
      * to fill in value for this property.
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4a093e6..918b5a3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5379,7 +5379,8 @@
             if (mTracePrefix == null) {
                 mTracePrefix = getClass().getSimpleName();
             }
-            Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber());
+            Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
+                    + Integer.toHexString(q.mEvent.getId()));
         }
     }
 
@@ -7986,12 +7987,13 @@
 
     private void deliverInputEvent(QueuedInputEvent q) {
         Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
-                q.mEvent.getSequenceNumber());
+                q.mEvent.getId());
 
         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
                     + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
-                    + q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber());
+                    + q.mEvent.getEventTimeNano() + " id=0x"
+                    + Integer.toHexString(q.mEvent.getId()));
         }
         try {
             if (mInputEventConsistencyVerifier != null) {
@@ -8032,7 +8034,7 @@
 
     private void finishInputEvent(QueuedInputEvent q) {
         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
-                q.mEvent.getSequenceNumber());
+                q.mEvent.getId());
 
         if (q.mReceiver != null) {
             boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 2d27a78..53541f7 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -369,10 +369,22 @@
     public abstract boolean getDisplayZoomControls();
 
     /**
-     * Enables or disables file access within WebView. File access is enabled by
-     * default.  Note that this enables or disables file system access only.
-     * Assets and resources are still accessible using file:///android_asset and
-     * file:///android_res.
+     * Enables or disables file access within WebView.
+     * Note that this enables or disables file system access only. Assets and resources
+     * are still accessible using file:///android_asset and file:///android_res.
+     * <p class="note">
+     * <b>Note:</b> Apps should not open {@code file://} URLs from any external source in
+     * WebView, don't enable this if your app accepts arbitrary URLs from external sources.
+     * It's recommended to always use
+     * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader">
+     * androidx.webkit.WebViewAssetLoader</a> to access files including assets and resources over
+     * {@code http(s)://} schemes, instead of {@code file://} URLs. To prevent possible security
+     * issues targeting {@link android.os.Build.VERSION_CODES#Q} and earlier, you should explicitly
+     * set this value to {@code false}.
+     * <p>
+     * The default value is {@code true} for apps targeting
+     * {@link android.os.Build.VERSION_CODES#Q} and below, and {@code false} when targeting
+     * {@link android.os.Build.VERSION_CODES#R} and above.
      */
     public abstract void setAllowFileAccess(boolean allow);
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 815cc5c..f3243aa 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13174,7 +13174,7 @@
         stream.addProperty("text:selectionStart", getSelectionStart());
         stream.addProperty("text:selectionEnd", getSelectionEnd());
         stream.addProperty("text:curTextColor", mCurTextColor);
-        stream.addProperty("text:text", mText == null ? null : mText.toString());
+        stream.addUserProperty("text:text", mText == null ? null : mText.toString());
         stream.addProperty("text:gravity", mGravity);
     }
 
diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java
index aa507e5..3464310 100644
--- a/core/java/com/android/internal/logging/InstanceIdSequence.java
+++ b/core/java/com/android/internal/logging/InstanceIdSequence.java
@@ -25,7 +25,7 @@
 import java.util.Random;
 
 /**
- * Generates random InstanceIds in range [0, instanceIdMax) for passing to
+ * Generates random InstanceIds in range [1, instanceIdMax] for passing to
  * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on
  * first use; try to give it a long lifetime. Safe for concurrent use.
  */
@@ -34,12 +34,12 @@
     private final Random mRandom = new SecureRandom();
 
     /**
-     * Constructs a sequence with identifiers [0, instanceIdMax).  Capped at INSTANCE_ID_MAX.
+     * Constructs a sequence with identifiers [1, instanceIdMax].  Capped at INSTANCE_ID_MAX.
      * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
-     *                      an all-zero sequence.
+     *                      an all-1 sequence.
      */
     public InstanceIdSequence(int instanceIdMax) {
-        mInstanceIdMax = min(max(0, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
+        mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
     }
 
     /**
@@ -47,7 +47,7 @@
      * @return new InstanceId
      */
     public InstanceId newInstanceId() {
-        return newInstanceIdInternal(mRandom.nextInt(mInstanceIdMax));
+        return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
     }
 
     /**
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 84acf9a..0a2b1d4 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -114,9 +114,9 @@
 
     uint32_t publishedSeq = mNextPublishedSeq++;
     status_t status =
-            mInputPublisher.publishKeyEvent(publishedSeq, event->getDeviceId(), event->getSource(),
-                                            event->getDisplayId(), event->getHmac(),
-                                            event->getAction(), event->getFlags(),
+            mInputPublisher.publishKeyEvent(publishedSeq, event->getId(), event->getDeviceId(),
+                                            event->getSource(), event->getDisplayId(),
+                                            event->getHmac(), event->getAction(), event->getFlags(),
                                             event->getKeyCode(), event->getScanCode(),
                                             event->getMetaState(), event->getRepeatCount(),
                                             event->getDownTime(), event->getEventTime());
@@ -138,12 +138,12 @@
     for (size_t i = 0; i <= event->getHistorySize(); i++) {
         publishedSeq = mNextPublishedSeq++;
         status_t status =
-                mInputPublisher.publishMotionEvent(publishedSeq, event->getDeviceId(),
-                                                   event->getSource(), event->getDisplayId(),
-                                                   event->getHmac(), event->getAction(),
-                                                   event->getActionButton(), event->getFlags(),
-                                                   event->getEdgeFlags(), event->getMetaState(),
-                                                   event->getButtonState(),
+                mInputPublisher.publishMotionEvent(publishedSeq, event->getId(),
+                                                   event->getDeviceId(), event->getSource(),
+                                                   event->getDisplayId(), event->getHmac(),
+                                                   event->getAction(), event->getActionButton(),
+                                                   event->getFlags(), event->getEdgeFlags(),
+                                                   event->getMetaState(), event->getButtonState(),
                                                    event->getClassification(), event->getXScale(),
                                                    event->getYScale(), event->getXOffset(),
                                                    event->getYOffset(), event->getXPrecision(),
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index bbe563e..54567e5 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -75,6 +75,7 @@
     jmethodID obtain;
     jmethodID recycle;
 
+    jfieldID mId;
     jfieldID mDeviceId;
     jfieldID mSource;
     jfieldID mDisplayId;
@@ -96,6 +97,7 @@
     ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
     jobject eventObj =
             env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
+                                        event->getId(),
                                         nanoseconds_to_milliseconds(event->getDownTime()),
                                         nanoseconds_to_milliseconds(event->getEventTime()),
                                         event->getAction(), event->getKeyCode(),
@@ -114,6 +116,7 @@
 
 status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
         KeyEvent* event) {
+    jint id = env->GetIntField(eventObj, gKeyEventClassInfo.mId);
     jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
     jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
     jint displayId = env->GetIntField(eventObj, gKeyEventClassInfo.mDisplayId);
@@ -131,7 +134,7 @@
     jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime);
     jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
 
-    event->initialize(deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
+    event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
                       metaState, repeatCount, milliseconds_to_nanoseconds(downTime),
                       milliseconds_to_nanoseconds(eventTime));
     return OK;
@@ -159,14 +162,18 @@
     return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str());
 }
 
+static jint android_view_KeyEvent_nativeNextId() {
+    return static_cast<jint>(InputEvent::nextId());
+}
 
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod g_methods[] = {
-    { "nativeKeyCodeToString", "(I)Ljava/lang/String;",
-        (void*)android_view_KeyEvent_nativeKeyCodeToString},
-    { "nativeKeyCodeFromString", "(Ljava/lang/String;)I",
-        (void*)android_view_KeyEvent_nativeKeyCodeFromString},
+        {"nativeKeyCodeToString", "(I)Ljava/lang/String;",
+         (void*)android_view_KeyEvent_nativeKeyCodeToString},
+        {"nativeKeyCodeFromString", "(Ljava/lang/String;)I",
+         (void*)android_view_KeyEvent_nativeKeyCodeFromString},
+        {"nativeNextId", "()I", (void*)android_view_KeyEvent_nativeNextId},
 };
 
 int register_android_view_KeyEvent(JNIEnv* env) {
@@ -175,10 +182,11 @@
 
     gKeyEventClassInfo.obtain =
             GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, "obtain",
-                                   "(JJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;");
+                                   "(IJJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;");
     gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz,
             "recycle", "()V");
 
+    gKeyEventClassInfo.mId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mId", "I");
     gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I");
     gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I");
     gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId",
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 3335fb2..9816d71 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -369,9 +369,10 @@
         env->DeleteLocalRef(pointerCoordsObj);
     }
 
-    event->initialize(deviceId, source, displayId, INVALID_HMAC, action, 0, flags, edgeFlags,
-                      metaState, buttonState, static_cast<MotionClassification>(classification),
-                      1 /*xScale*/, 1 /*yScale*/, xOffset, yOffset, xPrecision, yPrecision,
+    event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0,
+                      flags, edgeFlags, metaState, buttonState,
+                      static_cast<MotionClassification>(classification), 1 /*xScale*/, 1 /*yScale*/,
+                      xOffset, yOffset, xPrecision, yPrecision,
                       AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                       downTimeNanos, eventTimeNanos, pointerCount, pointerProperties,
                       rawPointerCoords);
@@ -592,6 +593,11 @@
     return reinterpret_cast<jlong>(destEvent);
 }
 
+static jint android_view_MotionEvent_nativeGetId(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return event->getId();
+}
+
 static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
     return event->getDeviceId();
@@ -790,6 +796,7 @@
         // --------------- @CriticalNative ------------------
 
         {"nativeCopy", "(JJZ)J", (void*)android_view_MotionEvent_nativeCopy},
+        {"nativeGetId", "(J)I", (void*)android_view_MotionEvent_nativeGetId},
         {"nativeGetDeviceId", "(J)I", (void*)android_view_MotionEvent_nativeGetDeviceId},
         {"nativeGetSource", "(J)I", (void*)android_view_MotionEvent_nativeGetSource},
         {"nativeSetSource", "(JI)V", (void*)android_view_MotionEvent_nativeSetSource},
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 08db454..e8a0b46 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -167,7 +167,7 @@
     optional WindowContainerProto window_container = 1;
     optional int32 id = 2;
     reserved 3; // stacks
-    optional DockedStackDividerControllerProto docked_stack_divider_controller = 4;
+    optional DockedStackDividerControllerProto docked_stack_divider_controller = 4 [deprecated=true];
     // Will be removed soon.
     optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
     /* non app windows */
@@ -229,7 +229,7 @@
 message DockedStackDividerControllerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional bool minimized_dock = 1;
+    optional bool minimized_dock = 1 [deprecated=true];
 }
 
 /* represents PinnedStackController */
diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto
index cd7173a..97350ef 100644
--- a/core/proto/android/service/appwidget.proto
+++ b/core/proto/android/service/appwidget.proto
@@ -36,4 +36,5 @@
     optional int32 minHeight = 7;
     optional int32 maxWidth = 8;
     optional int32 maxHeight = 9;
+    optional bool restoreCompleted = 10;
 }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 490892e..8023990 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2752,7 +2752,9 @@
 
     <!-- The amount to scale reduced scale snapshots for Overview and snapshot starting windows.
          Reduced scale snapshots are loaded before full screen snapshots to improve load times and
-         minimize the chance the user will see an empty task card. -->
+         minimize the chance the user will see an empty task card. If set to 0, reduced scale
+         snapshots are disabled, and snapshots will only be stored at config_highResTaskSnapshotScale
+         -->
     <item name="config_lowResTaskSnapshotScale" format="float" type="dimen">0.5</item>
 
     <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->
@@ -3957,14 +3959,14 @@
     <!-- Component name for the default module metadata provider on this device -->
     <string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string>
 
-    <!-- This is the default launcher component to use on secondary displays that support system
-         decorations.
-         This launcher activity must support multiple instances and have corresponding launch mode
-         set in AndroidManifest.
+    <!-- This is the default launcher package with an activity to use on secondary displays that
+         support system decorations.
+         This launcher package must have an activity that supports multiple instances and has
+         corresponding launch mode set in AndroidManifest.
          {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
-    <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
+    <string name="config_secondaryHomePackage" translatable="false">com.android.launcher3</string>
 
-    <!-- Force secondary home launcher specified in config_secondaryHomeComponent always. If this is
+    <!-- Force secondary home launcher specified in config_secondaryHomePackage always. If this is
          not set, secondary home launcher can be replaced by user. -->
     <bool name ="config_useSystemProvidedLauncherForSecondary">false</bool>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7690b94..3ed3a64e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3678,7 +3678,7 @@
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
 
   <!-- For Secondary Launcher -->
-  <java-symbol type="string" name="config_secondaryHomeComponent" />
+  <java-symbol type="string" name="config_secondaryHomePackage" />
   <java-symbol type="bool" name="config_useSystemProvidedLauncherForSecondary" />
 
   <java-symbol type="string" name="battery_saver_notification_channel_name" />
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index 14999c7..623008e 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -19,6 +19,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 
 import android.os.Parcel;
 
@@ -28,10 +29,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashSet;
+import java.util.Set;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KeyEventTest {
 
+    private static final int ID = 0xabcdef;
     private static final int DOWN_TIME = 50;
     private static final long EVENT_TIME = 100;
     private static final int ACTION = KeyEvent.ACTION_DOWN;
@@ -45,6 +50,8 @@
     private static final byte[] HMAC = null;
     private static final String CHARACTERS = null;
 
+    private static final int ID_SOURCE_MASK = 0x3 << 30;
+
     @Test
     public void testObtain() {
         KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
@@ -75,8 +82,7 @@
     public void testObtainWithDisplayId() {
         final int displayId = 5;
         KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
-                METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, null /* hmac*/,
-                CHARACTERS);
+                METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS);
         assertEquals(DOWN_TIME, keyEvent.getDownTime());
         assertEquals(EVENT_TIME, keyEvent.getEventTime());
         assertEquals(ACTION, keyEvent.getAction());
@@ -91,6 +97,52 @@
         assertEquals(CHARACTERS, keyEvent.getCharacters());
     }
 
+    /**
+     * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test
+     * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough.
+     * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for
+     * this test.
+     */
+    @Test
+    public void testObtainGeneratesUniqueId() {
+        Set<Integer> set = new HashSet<>();
+        for (int i = 0; i < 500; ++i) {
+            KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
+                    METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
+            assertFalse("Found duplicate ID in round " + i,
+                    set.contains(keyEvent.getId()));
+            set.add(keyEvent.getSequenceNumber());
+        }
+    }
+
+    @Test
+    public void testConstructorGeneratesUniqueId() {
+        Set<Integer> set = new HashSet<>();
+        for (int i = 0; i < 500; ++i) {
+            KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
+            assertFalse("Found duplicate sequence number in round " + i,
+                    set.contains(keyEvent.getId()));
+            set.add(keyEvent.getSequenceNumber());
+        }
+    }
+
+    @Test
+    public void testObtainGeneratesIdWithRightSource() {
+        for (int i = 0; i < 500; ++i) {
+            KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
+                    METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
+            assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
+        }
+    }
+
+    @Test
+    public void testConstructorGeneratesIdWithRightSource() {
+        for (int i = 0; i < 500; ++i) {
+            KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
+            assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
+        }
+    }
+
     @Test
     public void testParcelUnparcel() {
         KeyEvent key1 = createKey();
@@ -112,11 +164,12 @@
     }
 
     private static KeyEvent createKey() {
-        return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
-                METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
+        return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+                DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
     }
 
     private static void compareKeys(KeyEvent key1, KeyEvent key2) {
+        assertEquals(key1.getId(), key2.getId());
         assertEquals(key1.getDownTime(), key2.getDownTime());
         assertEquals(key1.getEventTime(), key2.getEventTime());
         assertEquals(key1.getAction(), key2.getAction());
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 9d09830..786ae89 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -23,6 +23,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 
 import android.view.MotionEvent.PointerCoords;
@@ -34,9 +35,13 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashSet;
+import java.util.Set;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class MotionEventTest {
+    private static final int ID_SOURCE_MASK = 0x3 << 30;
 
     @Test
     public void testObtainWithDisplayId() {
@@ -138,4 +143,30 @@
         assertEquals(30, event.getXCursorPosition(), 0.1);
         assertEquals(50, event.getYCursorPosition(), 0.1);
     }
+
+    /**
+     * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test
+     * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough.
+     * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for
+     * this test.
+     */
+    @Test
+    public void testObtainGeneratesUniqueId() {
+        Set<Integer> set = new HashSet<>();
+        for (int i = 0; i < 500; ++i) {
+            final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+                    ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+            assertFalse("Found duplicate ID in round " + i, set.contains(event.getId()));
+            set.add(event.getSequenceNumber());
+        }
+    }
+
+    @Test
+    public void testObtainGeneratesIdWithRightSource() {
+        for (int i = 0; i < 500; ++i) {
+            final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+                    ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+            assertEquals(0x3 << 30, ID_SOURCE_MASK & event.getId());
+        }
+    }
 }
diff --git a/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index 4d98603..0ffaa21 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -18,5 +18,6 @@
     <privapp-permissions package="com.android.documentsui">
         <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.MODIFY_QUIET_MODE"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 145fd8b..99605ad 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -697,6 +697,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-668956537": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/SurfaceFreezer.java"
+    },
     "-666510420": {
       "message": "With display frozen, orientationChangeComplete=%b",
       "level": "VERBOSE",
diff --git a/data/keyboards/Vendor_0079_Product_18d4.kl b/data/keyboards/Vendor_0079_Product_18d4.kl
new file mode 100644
index 0000000..b9a2b67
--- /dev/null
+++ b/data/keyboards/Vendor_0079_Product_18d4.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# GPD Win 2 X-Box Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_044f_Product_b326.kl b/data/keyboards/Vendor_044f_Product_b326.kl
new file mode 100644
index 0000000..d248d71
--- /dev/null
+++ b/data/keyboards/Vendor_044f_Product_b326.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Thrustmaster Gamepad GP XID
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_045e_Product_028f.kl b/data/keyboards/Vendor_045e_Product_028f.kl
new file mode 100644
index 0000000..cc5b33b
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_028f.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Microsoft X-Box 360 pad v2
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_046d_Product_c21e.kl b/data/keyboards/Vendor_046d_Product_c21e.kl
new file mode 100644
index 0000000..9980743
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c21e.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Logitech Gamepad F510
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_046d_Product_c242.kl b/data/keyboards/Vendor_046d_Product_c242.kl
new file mode 100644
index 0000000..51eb44a
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c242.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Logitech Chillstream Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_056e_Product_2004.kl b/data/keyboards/Vendor_056e_Product_2004.kl
new file mode 100644
index 0000000..9eaa36d
--- /dev/null
+++ b/data/keyboards/Vendor_056e_Product_2004.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Elecom JC-U3613M
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_06a3_Product_f51a.kl b/data/keyboards/Vendor_06a3_Product_f51a.kl
new file mode 100644
index 0000000..e52f257
--- /dev/null
+++ b/data/keyboards/Vendor_06a3_Product_f51a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Saitek P3600
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_4716.kl b/data/keyboards/Vendor_0738_Product_4716.kl
new file mode 100644
index 0000000..5f3d4aa
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_4716.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Wired Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_4718.kl b/data/keyboards/Vendor_0738_Product_4718.kl
new file mode 100644
index 0000000..756e1e7
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_4718.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Street Fighter IV FightStick SE
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_4726.kl b/data/keyboards/Vendor_0738_Product_4726.kl
new file mode 100644
index 0000000..9d8deb3
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_4726.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_4736.kl b/data/keyboards/Vendor_0738_Product_4736.kl
new file mode 100644
index 0000000..c556e25
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_4736.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz MicroCon Gamepad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_4740.kl b/data/keyboards/Vendor_0738_Product_4740.kl
new file mode 100644
index 0000000..cdb7268
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_4740.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Beat Pad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_9871.kl b/data/keyboards/Vendor_0738_Product_9871.kl
new file mode 100644
index 0000000..f404065
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_9871.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Portable Drum
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_b726.kl b/data/keyboards/Vendor_0738_Product_b726.kl
new file mode 100644
index 0000000..05b737f
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_b726.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Xbox controller - MW2
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_beef.kl b/data/keyboards/Vendor_0738_Product_beef.kl
new file mode 100644
index 0000000..f969e73
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_beef.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz JOYTECH NEO SE Advanced GamePad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_cb02.kl b/data/keyboards/Vendor_0738_Product_cb02.kl
new file mode 100644
index 0000000..bc2fc35
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_cb02.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Saitek Cyborg Rumble Pad - PC/Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_cb03.kl b/data/keyboards/Vendor_0738_Product_cb03.kl
new file mode 100644
index 0000000..dcbf6b7
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_cb03.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Saitek P3200 Rumble Pad - PC/Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_cb29.kl b/data/keyboards/Vendor_0738_Product_cb29.kl
new file mode 100644
index 0000000..fe81d1c
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_cb29.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Saitek Aviator Stick AV8R02
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0738_Product_f738.kl b/data/keyboards/Vendor_0738_Product_f738.kl
new file mode 100644
index 0000000..2c99380
--- /dev/null
+++ b/data/keyboards/Vendor_0738_Product_f738.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Super SFIV FightStick TE S
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_07ff_Product_ffff.kl b/data/keyboards/Vendor_07ff_Product_ffff.kl
new file mode 100644
index 0000000..637c01b
--- /dev/null
+++ b/data/keyboards/Vendor_07ff_Product_ffff.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz GamePad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0113.kl b/data/keyboards/Vendor_0e6f_Product_0113.kl
new file mode 100644
index 0000000..90e1f75
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0113.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Afterglow AX.1 Gamepad for Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_011f.kl b/data/keyboards/Vendor_0e6f_Product_011f.kl
new file mode 100644
index 0000000..8c63c6b
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_011f.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Gamepad Wired Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0131.kl b/data/keyboards/Vendor_0e6f_Product_0131.kl
new file mode 100644
index 0000000..368c3760
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0131.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP EA Sports Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0133.kl b/data/keyboards/Vendor_0e6f_Product_0133.kl
new file mode 100644
index 0000000..815902e
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0133.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Xbox 360 Wired Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0139.kl b/data/keyboards/Vendor_0e6f_Product_0139.kl
new file mode 100644
index 0000000..8e2ae13
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0139.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Afterglow Prismatic Wired Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_013a.kl b/data/keyboards/Vendor_0e6f_Product_013a.kl
new file mode 100644
index 0000000..3f81983
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_013a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Xbox One Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0146.kl b/data/keyboards/Vendor_0e6f_Product_0146.kl
new file mode 100644
index 0000000..6ddd056
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0146.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Wired Controller for Xbox One
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0147.kl b/data/keyboards/Vendor_0e6f_Product_0147.kl
new file mode 100644
index 0000000..6745b7c
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0147.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Marvel Xbox One Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0161.kl b/data/keyboards/Vendor_0e6f_Product_0161.kl
new file mode 100644
index 0000000..3f81983
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0161.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Xbox One Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0162.kl b/data/keyboards/Vendor_0e6f_Product_0162.kl
new file mode 100644
index 0000000..3f81983
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0162.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Xbox One Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0163.kl b/data/keyboards/Vendor_0e6f_Product_0163.kl
new file mode 100644
index 0000000..3f81983
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0163.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Xbox One Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0164.kl b/data/keyboards/Vendor_0e6f_Product_0164.kl
new file mode 100644
index 0000000..0fdfd32
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0164.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Battlefield One
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0165.kl b/data/keyboards/Vendor_0e6f_Product_0165.kl
new file mode 100644
index 0000000..f9731e0
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0165.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Titanfall 2
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0201.kl b/data/keyboards/Vendor_0e6f_Product_0201.kl
new file mode 100644
index 0000000..5b4c167
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0201.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Pelican PL-3601 'TSZ' Wired Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0213.kl b/data/keyboards/Vendor_0e6f_Product_0213.kl
new file mode 100644
index 0000000..9317346
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0213.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Afterglow Gamepad for Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_021f.kl b/data/keyboards/Vendor_0e6f_Product_021f.kl
new file mode 100644
index 0000000..f8d3f0c
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_021f.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Gamepad for Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0246.kl b/data/keyboards/Vendor_0e6f_Product_0246.kl
new file mode 100644
index 0000000..daf8e45
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0246.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Gamepad for Xbox One 2015
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_02a6.kl b/data/keyboards/Vendor_0e6f_Product_02a6.kl
new file mode 100644
index 0000000..99a5931
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_02a6.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Wired Controller for Xbox One - Camo Series
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_02ab.kl b/data/keyboards/Vendor_0e6f_Product_02ab.kl
new file mode 100644
index 0000000..071a56c
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_02ab.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Controller for Xbox One
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0301.kl b/data/keyboards/Vendor_0e6f_Product_0301.kl
new file mode 100644
index 0000000..a3b982d
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0301.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Logic3 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0346.kl b/data/keyboards/Vendor_0e6f_Product_0346.kl
new file mode 100644
index 0000000..6fefbf7
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0346.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Gamepad for Xbox One 2016
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0401.kl b/data/keyboards/Vendor_0e6f_Product_0401.kl
new file mode 100644
index 0000000..a3b982d
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0401.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Logic3 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0413.kl b/data/keyboards/Vendor_0e6f_Product_0413.kl
new file mode 100644
index 0000000..90e1f75
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0413.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Afterglow AX.1 Gamepad for Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_0501.kl b/data/keyboards/Vendor_0e6f_Product_0501.kl
new file mode 100644
index 0000000..35831d1
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_0501.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_f900.kl b/data/keyboards/Vendor_0e6f_Product_f900.kl
new file mode 100644
index 0000000..44848ba
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_f900.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Afterglow AX.1
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0f0d_Product_000a.kl b/data/keyboards/Vendor_0f0d_Product_000a.kl
new file mode 100644
index 0000000..b3aea04
--- /dev/null
+++ b/data/keyboards/Vendor_0f0d_Product_000a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori Co. DOA4 FightStick
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0f0d_Product_000c.kl b/data/keyboards/Vendor_0f0d_Product_000c.kl
new file mode 100644
index 0000000..49c3add
--- /dev/null
+++ b/data/keyboards/Vendor_0f0d_Product_000c.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori PadEX Turbo
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0f0d_Product_0067.kl b/data/keyboards/Vendor_0f0d_Product_0067.kl
new file mode 100644
index 0000000..0dfcceb
--- /dev/null
+++ b/data/keyboards/Vendor_0f0d_Product_0067.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# HORIPAD ONE
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1038_Product_1430.kl b/data/keyboards/Vendor_1038_Product_1430.kl
new file mode 100644
index 0000000..e635c1d
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1430.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# SteelSeries Stratus Duo
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1038_Product_1431.kl b/data/keyboards/Vendor_1038_Product_1431.kl
new file mode 100644
index 0000000..e635c1d
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1431.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# SteelSeries Stratus Duo
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_11c9_Product_55f0.kl b/data/keyboards/Vendor_11c9_Product_55f0.kl
new file mode 100644
index 0000000..dbb4a7e
--- /dev/null
+++ b/data/keyboards/Vendor_11c9_Product_55f0.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Nacon GC-100XF
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_12ab_Product_0301.kl b/data/keyboards/Vendor_12ab_Product_0301.kl
new file mode 100644
index 0000000..36956c1
--- /dev/null
+++ b/data/keyboards/Vendor_12ab_Product_0301.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP AFTERGLOW AX.1
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1430_Product_4748.kl b/data/keyboards/Vendor_1430_Product_4748.kl
new file mode 100644
index 0000000..dbe8308
--- /dev/null
+++ b/data/keyboards/Vendor_1430_Product_4748.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# RedOctane Guitar Hero X-plorer
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1430_Product_f801.kl b/data/keyboards/Vendor_1430_Product_f801.kl
new file mode 100644
index 0000000..a8f9146
--- /dev/null
+++ b/data/keyboards/Vendor_1430_Product_f801.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# RedOctane Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_146b_Product_0601.kl b/data/keyboards/Vendor_146b_Product_0601.kl
new file mode 100644
index 0000000..ea2f221
--- /dev/null
+++ b/data/keyboards/Vendor_146b_Product_0601.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# BigBen Interactive XBOX 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1532_Product_0037.kl b/data/keyboards/Vendor_1532_Product_0037.kl
new file mode 100644
index 0000000..39d8b2e
--- /dev/null
+++ b/data/keyboards/Vendor_1532_Product_0037.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Razer Sabertooth
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1532_Product_0a03.kl b/data/keyboards/Vendor_1532_Product_0a03.kl
new file mode 100644
index 0000000..75775e9
--- /dev/null
+++ b/data/keyboards/Vendor_1532_Product_0a03.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Razer Wildcat
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_15e4_Product_3f00.kl b/data/keyboards/Vendor_15e4_Product_3f00.kl
new file mode 100644
index 0000000..0d641cf
--- /dev/null
+++ b/data/keyboards/Vendor_15e4_Product_3f00.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Power A Mini Pro Elite
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_15e4_Product_3f0a.kl b/data/keyboards/Vendor_15e4_Product_3f0a.kl
new file mode 100644
index 0000000..9e98aee
--- /dev/null
+++ b/data/keyboards/Vendor_15e4_Product_3f0a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Xbox Airflo wired controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_15e4_Product_3f10.kl b/data/keyboards/Vendor_15e4_Product_3f10.kl
new file mode 100644
index 0000000..7fb0fea
--- /dev/null
+++ b/data/keyboards/Vendor_15e4_Product_3f10.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Batarang Xbox 360 controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_162e_Product_beef.kl b/data/keyboards/Vendor_162e_Product_beef.kl
new file mode 100644
index 0000000..e7fab5d
--- /dev/null
+++ b/data/keyboards/Vendor_162e_Product_beef.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Joytech Neo-Se Take2
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_0002.kl b/data/keyboards/Vendor_1bad_Product_0002.kl
new file mode 100644
index 0000000..d8eaaba
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_0002.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Harmonix Rock Band Guitar
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f021.kl b/data/keyboards/Vendor_1bad_Product_f021.kl
new file mode 100644
index 0000000..9fd688b
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f021.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Cats Ghost Recon FS GamePad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f025.kl b/data/keyboards/Vendor_1bad_Product_f025.kl
new file mode 100644
index 0000000..03aab44
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f025.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Mad Catz Call Of Duty
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f028.kl b/data/keyboards/Vendor_1bad_Product_f028.kl
new file mode 100644
index 0000000..5173331
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f028.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Street Fighter IV FightPad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f038.kl b/data/keyboards/Vendor_1bad_Product_f038.kl
new file mode 100644
index 0000000..79e147d
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f038.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Street Fighter IV FightStick TE
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f501.kl b/data/keyboards/Vendor_1bad_Product_f501.kl
new file mode 100644
index 0000000..1282532
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f501.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# HoriPad EX2 Turbo
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f506.kl b/data/keyboards/Vendor_1bad_Product_f506.kl
new file mode 100644
index 0000000..3a9d462
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f506.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori Real Arcade Pro.EX Premium VLX
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f900.kl b/data/keyboards/Vendor_1bad_Product_f900.kl
new file mode 100644
index 0000000..9cfceb4
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f900.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Harmonix Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f901.kl b/data/keyboards/Vendor_1bad_Product_f901.kl
new file mode 100644
index 0000000..86d45e5
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f901.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Gamestop Xbox 360 Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f903.kl b/data/keyboards/Vendor_1bad_Product_f903.kl
new file mode 100644
index 0000000..f61c050
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f903.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Tron Xbox 360 controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_f904.kl b/data/keyboards/Vendor_1bad_Product_f904.kl
new file mode 100644
index 0000000..3e02a24
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f904.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PDP Versus Fighting Pad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_fa01.kl b/data/keyboards/Vendor_1bad_Product_fa01.kl
new file mode 100644
index 0000000..517413d
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_fa01.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# MadCatz GamePad
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_fd00.kl b/data/keyboards/Vendor_1bad_Product_fd00.kl
new file mode 100644
index 0000000..fc6a4f8
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_fd00.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Razer Onza TE
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_1bad_Product_fd01.kl b/data/keyboards/Vendor_1bad_Product_fd01.kl
new file mode 100644
index 0000000..8882abf
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_fd01.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Razer Onza
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5300.kl b/data/keyboards/Vendor_24c6_Product_5300.kl
new file mode 100644
index 0000000..303e906
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5300.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA MINI PROEX Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5303.kl b/data/keyboards/Vendor_24c6_Product_5303.kl
new file mode 100644
index 0000000..9e98aee
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5303.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Xbox Airflo wired controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_530a.kl b/data/keyboards/Vendor_24c6_Product_530a.kl
new file mode 100644
index 0000000..aa88515
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_530a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Xbox 360 Pro EX Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_531a.kl b/data/keyboards/Vendor_24c6_Product_531a.kl
new file mode 100644
index 0000000..09a5c6a
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_531a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA Pro Ex
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5397.kl b/data/keyboards/Vendor_24c6_Product_5397.kl
new file mode 100644
index 0000000..66b896a3
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5397.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# FUS1ON Tournament Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_541a.kl b/data/keyboards/Vendor_24c6_Product_541a.kl
new file mode 100644
index 0000000..24271fb
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_541a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA Xbox One Mini Wired Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_542a.kl b/data/keyboards/Vendor_24c6_Product_542a.kl
new file mode 100644
index 0000000..623bd137
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_542a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Xbox ONE spectra
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_543a.kl b/data/keyboards/Vendor_24c6_Product_543a.kl
new file mode 100644
index 0000000..59769c4
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_543a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA Xbox One wired controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5500.kl b/data/keyboards/Vendor_24c6_Product_5500.kl
new file mode 100644
index 0000000..d76d7d0
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5500.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori XBOX 360 EX 2 with Turbo
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5501.kl b/data/keyboards/Vendor_24c6_Product_5501.kl
new file mode 100644
index 0000000..64d901a
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5501.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori Real Arcade Pro VX-SA
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5506.kl b/data/keyboards/Vendor_24c6_Product_5506.kl
new file mode 100644
index 0000000..bfb23c3
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5506.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori SOULCALIBUR V Stick
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_550d.kl b/data/keyboards/Vendor_24c6_Product_550d.kl
new file mode 100644
index 0000000..24852b0
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_550d.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Hori GEM Xbox controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_551a.kl b/data/keyboards/Vendor_24c6_Product_551a.kl
new file mode 100644
index 0000000..5e338a5
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_551a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA FUSION Pro Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_561a.kl b/data/keyboards/Vendor_24c6_Product_561a.kl
new file mode 100644
index 0000000..57b7ddc
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_561a.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# PowerA FUSION Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5b02.kl b/data/keyboards/Vendor_24c6_Product_5b02.kl
new file mode 100644
index 0000000..bcf354d
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5b02.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Thrustmaster, Inc. GPX Controller
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_5d04.kl b/data/keyboards/Vendor_24c6_Product_5d04.kl
new file mode 100644
index 0000000..39d8b2e
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_5d04.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Razer Sabertooth
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/data/keyboards/Vendor_24c6_Product_fafe.kl b/data/keyboards/Vendor_24c6_Product_fafe.kl
new file mode 100644
index 0000000..f8d3f0c
--- /dev/null
+++ b/data/keyboards/Vendor_24c6_Product_fafe.kl
@@ -0,0 +1,58 @@
+# 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.
+
+#
+# Rock Candy Gamepad for Xbox 360
+# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708)
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315   BUTTON_START
+
+# Xbox key
+key 316   BUTTON_MODE
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 73769be..7a684b3 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -18,11 +18,13 @@
 
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
 import android.media.tv.TvInputService;
 import android.media.tv.tuner.TunerConstants.Result;
 import android.media.tv.tuner.dvr.DvrPlayback;
@@ -45,6 +47,8 @@
 import android.os.Looper;
 import android.os.Message;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -67,6 +71,22 @@
     private static final int MSG_ON_FILTER_STATUS = 3;
     private static final int MSG_ON_LNB_EVENT = 4;
 
+    /** @hide */
+    @IntDef(prefix = "DVR_TYPE_", value = {DVR_TYPE_RECORD, DVR_TYPE_PLAYBACK})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DvrType {}
+
+    /**
+     * DVR for recording.
+     * @hide
+     */
+    public static final int DVR_TYPE_RECORD = Constants.DvrType.RECORD;
+    /**
+     * DVR for playback of recorded programs.
+     * @hide
+     */
+    public static final int DVR_TYPE_PLAYBACK = Constants.DvrType.PLAYBACK;
+
     static {
         System.loadLibrary("media_tv_tuner");
         nativeInit();
diff --git a/media/java/android/media/tv/tuner/dvr/Dvr.java b/media/java/android/media/tv/tuner/dvr/Dvr.java
deleted file mode 100644
index 4183e3b..0000000
--- a/media/java/android/media/tv/tuner/dvr/Dvr.java
+++ /dev/null
@@ -1,159 +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.dvr;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
-import android.media.tv.tuner.TunerConstants.Result;
-import android.media.tv.tuner.filter.Filter;
-import android.os.ParcelFileDescriptor;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Digital Video Record (DVR) interface provides record control on Demux's output buffer and
- * playback control on Demux's input buffer.
- *
- * @hide
- */
-@SystemApi
-public class Dvr implements AutoCloseable {
-
-    /** @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;
-
-
-    final int mType;
-    long mNativeContext;
-
-    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);
-
-    protected Dvr(int type) {
-        mType = type;
-    }
-
-    /**
-     * 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.
-     */
-    public void close() {
-        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());
-    }
-
-    @Type
-    int getType() {
-        return mType;
-    }
-}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index eb31574..7c15bb7 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -21,6 +21,9 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.filter.Filter;
+import android.os.ParcelFileDescriptor;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -33,7 +36,7 @@
  * @hide
  */
 @SystemApi
-public class DvrPlayback extends Dvr {
+public class DvrPlayback implements AutoCloseable {
 
 
     /** @hide */
@@ -66,17 +69,110 @@
      */
     public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
 
+    long mNativeContext;
 
-
+    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 long nativeRead(long size);
     private native long nativeRead(byte[] bytes, long offset, long size);
 
     private DvrPlayback() {
-        super(Dvr.TYPE_PLAYBACK);
     }
 
 
     /**
+     * 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.
+     */
+    @Override
+    public void close() {
+        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.
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 3128ca5..52ef5e6 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -19,6 +19,9 @@
 import android.annotation.BytesLong;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.filter.Filter;
+import android.os.ParcelFileDescriptor;
 
 /**
  * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer.
@@ -26,12 +29,108 @@
  * @hide
  */
 @SystemApi
-public class DvrRecorder extends Dvr {
+public class DvrRecorder implements AutoCloseable {
+    long mNativeContext;
+
+    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 long nativeWrite(long size);
     private native long nativeWrite(byte[] bytes, long offset, long size);
 
     private DvrRecorder() {
-        super(Dvr.TYPE_RECORD);
+    }
+
+
+    /**
+     * 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.
+     */
+    @Override
+    public void close() {
+        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());
     }
 
     /**
diff --git a/media/java/android/media/tv/tuner/dvr/DvrSettings.java b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
index f9dc682..362b108 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrSettings.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
@@ -30,7 +30,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * DVR settings used to configure {@link Dvr}.
+ * DVR settings used to configure {@link DvrPlayback} and {@link DvrRecorder}.
  *
  * @hide
  */
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 a4eada4..f39f912 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -122,6 +122,7 @@
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -324,6 +325,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            PhoneStatusBarPolicy phoneStatusBarPolicy,
             DismissCallbackRegistry dismissCallbackRegistry,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             /* Car Settings injected components. */
@@ -407,6 +409,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                phoneStatusBarPolicy,
                 dismissCallbackRegistry,
                 statusBarTouchableRegionManager);
         mUserSwitcherController = userSwitcherController;
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 7294965..843e7c5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -82,6 +82,7 @@
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -197,6 +198,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            PhoneStatusBarPolicy phoneStatusBarPolicy,
             DismissCallbackRegistry dismissCallbackRegistry,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             CarServiceProvider carServiceProvider,
@@ -278,6 +280,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                phoneStatusBarPolicy,
                 dismissCallbackRegistry,
                 statusBarTouchableRegionManager,
                 carServiceProvider,
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6d11461..2297ddf 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -892,9 +892,9 @@
     <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
     <string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string>
 
-    <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] -->
+    <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=60] -->
     <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string>
-    <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] -->
+    <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=NONE] -->
     <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string>
 
     <!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 3f55cea..8bf48e59 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -68,6 +68,7 @@
 
     private WifiInfo mWifiInfo;
     public boolean enabled;
+    public boolean isCaptivePortal;
     public int state;
     public boolean connected;
     public String ssid;
@@ -155,9 +156,11 @@
     private void updateStatusLabel() {
         final NetworkCapabilities networkCapabilities
                 = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork());
+        isCaptivePortal = false;
         if (networkCapabilities != null) {
             if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
                 statusLabel = mContext.getString(R.string.wifi_status_sign_in_required);
+                isCaptivePortal = true;
                 return;
             } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
                 statusLabel = mContext.getString(R.string.wifi_limited_connection);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 0f2ee6a..610165a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -268,6 +268,7 @@
                     Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                     Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
                     Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+                    Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
                     Settings.Global.ERROR_LOGCAT_PREFIX,
diff --git a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
index 7964609..015e9f9 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
@@ -16,6 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_selected="true"
-          android:color="@color/notification_guts_priority_button_bg_stroke_color_selected" />
+          android:color="?android:attr/colorAccent" />
     <item android:color="@color/notification_guts_priority_button_bg_stroke_color" />
 </selector>
diff --git a/packages/SystemUI/res/color/notification_guts_priority_contents.xml b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
index 56c43f0..42f0189 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_contents.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
@@ -16,6 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_selected="true"
-          android:color="@color/notification_guts_priority_button_content_color_selected" />
+          android:color="?android:attr/colorAccent" />
     <item android:color="@color/notification_guts_priority_button_content_color" />
 </selector>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
index 1730dce..2fe6c7b 100644
--- a/packages/SystemUI/res/drawable/notification_guts_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -16,7 +16,7 @@
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/notification_guts_bg_color" />
+    <solid android:color="@color/notification_material_background_color" />
     <!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners -->
     <corners android:radius="1dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml b/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml
new file mode 100644
index 0000000..e3d010e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?android:attr/colorControlHighlight">
+   <item>
+      <shape>
+         <solid android:color="@color/qs_user_detail_avatar_frame" />
+
+         <padding
+                 android:left="1dp"
+                 android:right="1dp"
+                 android:bottom="1dp"
+                 android:top="1dp" />
+
+         <corners android:radius="48dp" />
+      </shape>
+   </item>
+</ripple>
diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
new file mode 100644
index 0000000..1f38b1e
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<!-- LinearLayout -->
+<com.android.systemui.statusbar.policy.KeyguardUserDetailItemView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:sysui="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="8dp"
+        android:layout_marginEnd="8dp"
+        android:gravity="end|center_vertical"
+        android:clickable="true"
+        android:background="@drawable/rounded_user_switcher_bg"
+        sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
+        sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated">
+    <TextView android:id="@+id/user_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="13dp"
+            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
+            />
+    <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
+            android:layout_width="@dimen/framed_avatar_size"
+            android:layout_height="@dimen/framed_avatar_size"
+            android:contentDescription="@null"
+            sysui:badgeDiameter="18dp"
+            sysui:badgeMargin="1dp" />
+</com.android.systemui.statusbar.policy.KeyguardUserDetailItemView>
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
index 82a0115..bfa252c 100644
--- a/packages/SystemUI/res/layout/app_ops_info.xml
+++ b/packages/SystemUI/res/layout/app_ops_info.xml
@@ -26,7 +26,7 @@
         android:orientation="vertical"
         android:paddingStart="@*android:dimen/notification_content_margin_start"
         android:paddingEnd="@*android:dimen/notification_content_margin_end"
-        android:background="@color/notification_guts_bg_color"
+        android:background="@color/notification_material_background_color"
         android:theme="@*android:style/Theme.DeviceDefault.Light">
 
     <!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index a7379be..6533c18 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -70,12 +70,14 @@
             android:layout_height="match_parent"
             android:padding="4dp">
 
-            <TextView
+            <Button
+                android:id="@+id/other_apps"
+                android:visibility="gone"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
+                android:gravity="center_vertical"
                 android:text="See other apps"
-                android:textAppearance="@style/TextAppearance.Control.Title"
-                android:textColor="?android:attr/colorPrimary"
+                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintStart_toStartOf="parent"/>
@@ -85,6 +87,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:text="Done"
+                style="@*android:style/Widget.DeviceDefault.Button.Colored"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toEndOf="parent"/>
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index 62056e6..aab32f4 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -14,97 +14,26 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<androidx.constraintlayout.widget.ConstraintLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
 
     <TextView
-        android:id="@+id/error_message"
+        android:id="@+id/status_message"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:text="@string/controls_favorite_load_error"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:visibility="gone"
         android:gravity="center_horizontal"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/text_favorites"
     />
 
-    <TextView
-        android:id="@+id/text_favorites"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:text="@string/controls_favorite_header_favorites"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textAllCaps="true"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/divider1"
-        app:layout_constraintTop_toBottomOf="@id/error_message"
-        />
-
-    <View
-        android:id="@+id/divider1"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/controls_app_divider_height"
-        android:layout_gravity="center_horizontal|top"
-        android:background="?android:attr/listDivider"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/listFavorites"
-        app:layout_constraintTop_toBottomOf="@id/text_favorites"
-        />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/listFavorites"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:nestedScrollingEnabled="false"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/text_all"
-        app:layout_constraintTop_toBottomOf="@id/divider1"/>
-
-    <TextView
-        android:id="@+id/text_all"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:text="@string/controls_favorite_header_all"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textAllCaps="true"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/divider2"
-        app:layout_constraintTop_toBottomOf="@id/listFavorites"
-        />
-
-    <View
-        android:id="@+id/divider2"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/controls_app_divider_height"
-        android:layout_gravity="center_horizontal|top"
-        android:background="?android:attr/listDivider"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/listAll"
-        app:layout_constraintTop_toBottomOf="@id/text_all"
-        />
-
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/listAll"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:nestedScrollingEnabled="false"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/divider2"/>
+        android:nestedScrollingEnabled="false"/>
 
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index fb38e1c..b1e5165 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -27,8 +27,6 @@
         android:gravity="center_vertical"
         android:clickable="true"
         android:background="@drawable/ripple_drawable"
-        android:clipChildren="false"
-        android:clipToPadding="false"
         sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
         sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated">
     <TextView android:id="@+id/user_name"
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 87de9d4..5d03eee 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,8 +24,7 @@
     android:clipChildren="false"
     android:clipToPadding="true"
     android:orientation="vertical"
-    android:paddingStart="@*android:dimen/notification_content_margin_start"
-    android:background="@color/notification_guts_bg_color">
+    android:paddingStart="@*android:dimen/notification_content_margin_start">
 
     <!-- Package Info -->
     <RelativeLayout
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index ffe2eee..c350ed2 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -21,7 +21,7 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:clickable="true"
-    android:background="@color/notification_guts_bg_color"
+    android:background="@color/notification_material_background_color"
     android:theme="@style/Theme.SystemUI">
 
     <RelativeLayout
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 4fae3c5..f8db97d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -24,7 +24,6 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/status_bar_height"
     android:id="@+id/status_bar"
-    android:background="@drawable/system_bar_background"
     android:orientation="vertical"
     android:focusable="false"
     android:descendantFocusability="afterDescendants"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 8fee2cf9..7142929 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -28,5 +28,6 @@
     <FrameLayout
         android:id="@+id/status_bar_container"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
+        android:layout_height="wrap_content"
+        android:background="@drawable/system_bar_background" />
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 9a66e8b..9b0fe46 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -39,23 +39,16 @@
     <!-- The color of the ripples on the untinted notifications -->
     <color name="notification_ripple_untinted_color">#30ffffff</color>
 
-    <!-- The "inside" of a notification, reached via longpress -->
-    <color name="notification_guts_bg_color">@color/GM2_grey_900</color>
-
     <!-- The color of the text inside a notification -->
     <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
 
     <color name="notification_guts_link_icon_tint">@color/GM2_grey_500</color>
     <color name="notification_guts_sub_text_color">@color/GM2_grey_300</color>
     <color name="notification_guts_header_text_color">@color/GM2_grey_200</color>
-    <color name="notification_guts_info_button_color">@color/GM2_blue_300</color>
     <color name="notification_guts_priority_button_content_color">@color/GM2_grey_500</color>
-    <color name="notification_guts_priority_button_content_color_selected">@color/GM2_blue_300</color>
     <color name="notification_guts_priority_button_bg_fill_color">@color/transparent</color>
     <color name="notification_guts_priority_button_bg_fill_color_selected">@color/GM2_grey_800</color>
     <color name="notification_guts_priority_button_bg_stroke_color">@color/GM2_grey_700</color>
-    <color name="notification_guts_priority_button_bg_stroke_color_selected">@color/GM2_blue_300</color>
-
     <color name="notification_section_header_label_color">@color/GM2_grey_200</color>
     <color name="notification_section_clear_all_btn_color">@color/GM2_grey_500</color>
     <color name="notification_channel_dialog_separator">@color/GM2_grey_700</color>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 23b64e3..b375364 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -22,4 +22,28 @@
     <style name="UserDetailView">
         <item name="numColumns">4</item>
     </style>
+
+    <style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
+        <item name="android:textSize">@dimen/kg_user_switcher_text_size</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textColor">?attr/wallpaperTextColor</item>
+    </style>
+
+    <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.Activated">
+        <item name="android:fontWeight">700</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+
+    <style name="TextAppearance.QS.UserSwitcher">
+        <item name="android:textSize">@dimen/qs_detail_item_primary_text_size</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+    </style>
+
+    <style name="TextAppearance.QS.UserSwitcher.Activated">
+        <item name="android:fontWeight">700</item>
+        <item name="android:textStyle">bold</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 43ceb4e..73e49ce 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -88,21 +88,16 @@
     <!-- The color of the text inside a notification -->
     <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_light</color>
 
-    <!-- The "inside" of a notification, reached via longpress -->
-    <color name="notification_guts_bg_color">@color/GM2_grey_50</color>
 
     <color name="notification_guts_link_icon_tint">@color/GM2_grey_700</color>
     <color name="notification_guts_sub_text_color">@color/GM2_grey_700</color>
     <color name="notification_guts_header_text_color">@color/GM2_grey_900</color>
     <color name="notification_silence_color">#FF32c1de</color>
     <color name="notification_alert_color">#FFF87B2B</color>
-    <color name="notification_guts_info_button_color">@color/GM2_blue_700</color>
     <color name="notification_guts_priority_button_content_color">@color/GM2_grey_700</color>
-    <color name="notification_guts_priority_button_content_color_selected">@color/GM2_blue_700</color>
     <color name="notification_guts_priority_button_bg_fill_color">@color/transparent</color>
     <color name="notification_guts_priority_button_bg_fill_color_selected">#FFFFFF</color>
     <color name="notification_guts_priority_button_bg_stroke_color">@color/GM2_grey_300</color>
-    <color name="notification_guts_priority_button_bg_stroke_color_selected">@color/GM2_blue_600</color>
 
     <color name="notification_section_header_label_color">@color/GM2_grey_900</color>
     <color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8de2df5..8cb0c02 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -201,6 +201,13 @@
          always-on display) -->
     <string name="doze_brightness_sensor_type" translatable="false"></string>
 
+    <!-- Override value to use for proximity sensor.  -->
+    <string name="proximity_sensor_type" translatable="false"></string>
+
+    <!-- If using proximity_sensor_type, specifies a threshold value to distinguish near and
+         far break points. A sensor value less than this is considered "near". -->
+    <item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item>
+
     <!-- Doze: pulse parameter - how long does it take to fade in? -->
     <integer name="doze_pulse_duration_in">130</integer>
 
@@ -464,6 +471,9 @@
     <!-- Allow dragging the PIP to a location to close it -->
     <bool name="config_pipEnableDismissDragToEdge">true</bool>
 
+    <!-- Alow PIP to resize to a slightly bigger state upon touch/showing the menu -->
+    <bool name="config_pipEnableResizeForMenu">true</bool>
+
     <!-- SystemUI Plugins that can be loaded on user builds. -->
     <string-array name="config_pluginWhitelist" translatable="false">
         <item>com.android.systemui</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4aafec8..ff28b4d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2614,8 +2614,8 @@
     <string name="controls_providers_subtitle">Choose an app from which to add controls</string>
     <!-- Number of favorites for controls management screen [CHAR LIMIT=NONE]-->
     <plurals name="controls_number_of_favorites">
-        <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> current favorite.</item>
-        <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> current favorites.</item>
+        <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> control added.</item>
+        <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> controls added.</item>
     </plurals>
 
     <!-- Controls management controls screen default title [CHAR LIMIT=30] -->
@@ -2626,6 +2626,10 @@
     <string name="controls_favorite_header_favorites">Favorites</string>
     <!-- Controls management controls screen all header [CHAR LIMIT=50] -->
     <string name="controls_favorite_header_all">All</string>
-    <!-- Controls management controls screen error on load message [CHAR LIMIT=50] -->
+    <!-- Controls management controls screen error on load message [CHAR LIMIT=60] -->
     <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string>
+    <!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] -->
+    <string name="controls_favorite_other_zone_header">Other</string>
+
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 36c4526..d9b1452 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -514,7 +514,7 @@
     <style name="TextAppearance.NotificationInfo.Button">
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@color/notification_guts_info_button_color</item>
+        <item name="android:textColor">?android:attr/colorAccent</item>
         <item name="android:background">@drawable/btn_borderless_rect</item>
         <item name="android:gravity">center_vertical</item>
         <item name="android:focusable">true</item>
@@ -550,7 +550,7 @@
     <style name="TextAppearance.NotificationImportanceButton">
         <item name="android:textSize">@dimen/notification_importance_button_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
-        <item name="android:textColor">@color/notification_guts_priority_contents</item>
+        <item name="android:textColor">?android:attr/colorAccent</item>
         <item name="android:gravity">center</item>
     </style>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 4474a49..eca6ebf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -62,7 +62,9 @@
         orientation = snapshot.getOrientation();
         rotation = snapshot.getRotation();
         reducedResolution = snapshot.isLowResolution();
-        scale = snapshot.getScale();
+        // TODO(b/149579527): Pass task size instead of computing scale.
+        // Assume width and height were scaled the same; compute scale only for width
+        scale = (float) thumbnail.getWidth() / snapshot.getTaskSize().x;
         isRealSnapshot = snapshot.isRealSnapshot();
         isTranslucent = snapshot.isTranslucent();
         windowingMode = snapshot.getWindowingMode();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index a130092..49e3e57 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -370,8 +370,7 @@
             Rect initialBounds) {
         try {
             return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId,
-                    createMode, true /* onTop */, false /* animate */, initialBounds,
-                    true /* showRecents */);
+                    true /* onTop */);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 6cd6118..bbb83c7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -61,14 +61,6 @@
         }
     }
 
-    public void setSplitScreenMinimized(boolean minimized) {
-        try {
-            mAnimationController.setSplitScreenMinimized(minimized);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to set minimize dock", e);
-        }
-    }
-
     public void hideCurrentInputMethod() {
         try {
             mAnimationController.hideCurrentInputMethod();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index e28b1e2..d64bf77 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -191,18 +191,6 @@
     }
 
     /**
-     * Registers a docked stack listener with the system.
-     */
-    public void registerDockedStackListener(DockedStackListenerCompat listener) {
-        try {
-            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
-                    listener.mListener);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to register docked stack listener");
-        }
-    }
-
-    /**
      * Adds a pinned stack listener, which will receive updates from the window manager service
      * along with any other pinned stack listeners that were added via this method.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 4473b01..dbcdead 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -20,7 +20,9 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
@@ -94,18 +96,28 @@
         private EglHelper mEglHelper;
         private StatusBarStateController mController;
         private final Runnable mFinishRenderingTask = this::finishRendering;
-        private final boolean mNeedTransition;
         private boolean mShouldStopTransition;
-        @VisibleForTesting
-        final boolean mIsHighEndGfx;
-        private final boolean mDisplayNeedsBlanking;
         private final DisplayInfo mDisplayInfo = new DisplayInfo();
         private final Object mMonitor = new Object();
+        @VisibleForTesting
+        boolean mIsHighEndGfx;
+        private boolean mDisplayNeedsBlanking;
+        private boolean mNeedTransition;
         private boolean mNeedRedraw;
         // This variable can only be accessed in synchronized block.
         private boolean mWaitingForRendering;
 
         GLEngine(Context context, DozeParameters dozeParameters) {
+            init(dozeParameters);
+        }
+
+        @VisibleForTesting
+        GLEngine(DozeParameters dozeParameters, Handler handler) {
+            super(SystemClock::elapsedRealtime, handler);
+            init(dozeParameters);
+        }
+
+        private void init(DozeParameters dozeParameters) {
             mIsHighEndGfx = ActivityManager.isHighEndGfx();
             mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking();
             mNeedTransition = mIsHighEndGfx && !mDisplayNeedsBlanking;
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 10ae343..f0a82c5 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -164,7 +164,7 @@
         get(context).unregisterOnSharedPreferenceChangeListener(listener);
     }
 
-    private static SharedPreferences get(Context context) {
+    public static SharedPreferences get(Context context) {
         return context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 0ac1c12..79b691b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -39,6 +39,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingPlugin;
 import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.sensors.ProximitySensor;
@@ -69,6 +70,7 @@
     private final DockManager mDockManager;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private Executor mUiBgExecutor;
+    private final StatusBarStateController mStatusBarStateController;
 
     @Inject
     FalsingManagerProxy(Context context, PluginManager pluginManager, @Main Executor executor,
@@ -76,12 +78,14 @@
             DeviceConfigProxy deviceConfig, DockManager dockManager,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             DumpManager dumpManager,
-            @UiBackground Executor uiBgExecutor) {
+            @UiBackground Executor uiBgExecutor,
+            StatusBarStateController statusBarStateController) {
         mDisplayMetrics = displayMetrics;
         mProximitySensor = proximitySensor;
         mDockManager = dockManager;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mUiBgExecutor = uiBgExecutor;
+        mStatusBarStateController = statusBarStateController;
         mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
         mProximitySensor.setSensorDelay(SensorManager.SENSOR_DELAY_GAME);
         mDeviceConfig = deviceConfig;
@@ -143,7 +147,8 @@
                     mKeyguardUpdateMonitor,
                     mProximitySensor,
                     mDeviceConfig,
-                    mDockManager
+                    mDockManager,
+                    mStatusBarStateController
             );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index a084ae6..ec81b9f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -32,6 +32,8 @@
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.sensors.ProximitySensor;
 
@@ -59,6 +61,7 @@
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ProximitySensor mProximitySensor;
     private final DockManager mDockManager;
+    private final StatusBarStateController mStatusBarStateController;
     private boolean mSessionStarted;
     private MetricsLogger mMetricsLogger;
     private int mIsFalseTouchCalls;
@@ -88,15 +91,29 @@
             };
     private boolean mPreviousResult = false;
 
+    private StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+        @Override
+        public void onStateChanged(int newState) {
+            logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
+            mState = newState;
+            updateSessionActive();
+        }
+    };
+    private int mState;
+
     public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
             KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor,
             DeviceConfigProxy deviceConfigProxy,
-            DockManager dockManager) {
+            DockManager dockManager, StatusBarStateController statusBarStateController) {
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDataProvider = falsingDataProvider;
         mProximitySensor = proximitySensor;
         mDockManager = dockManager;
+        mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mState = mStatusBarStateController.getState();
 
         mMetricsLogger = new MetricsLogger();
         mClassifiers = new ArrayList<>();
@@ -116,13 +133,12 @@
         mProximitySensor.register(mSensorEventListener);
     }
 
-
     private void unregisterSensors() {
         mProximitySensor.unregister(mSensorEventListener);
     }
 
     private void sessionStart() {
-        if (!mSessionStarted && !mShowingAod && mScreenOn) {
+        if (!mSessionStarted && shouldSessionBeActive()) {
             logDebug("Starting Session");
             mSessionStarted = true;
             mJustUnlockedWithFace = false;
@@ -145,6 +161,19 @@
         }
     }
 
+
+    private void updateSessionActive() {
+        if (shouldSessionBeActive()) {
+            sessionStart();
+        } else {
+            sessionEnd();
+        }
+    }
+
+    private boolean shouldSessionBeActive() {
+        return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
+    }
+
     private void updateInteractionType(@Classifier.InteractionType int type) {
         logDebug("InteractionType: " + type);
         mDataProvider.setInteractionType(type);
@@ -232,11 +261,7 @@
     @Override
     public void setShowingAod(boolean showingAod) {
         mShowingAod = showingAod;
-        if (showingAod) {
-            sessionEnd();
-        } else {
-            sessionStart();
-        }
+        updateSessionActive();
     }
 
     @Override
@@ -343,13 +368,13 @@
     @Override
     public void onScreenTurningOn() {
         mScreenOn = true;
-        sessionStart();
+        updateSessionActive();
     }
 
     @Override
     public void onScreenOff() {
         mScreenOn = false;
-        sessionEnd();
+        updateSessionActive();
     }
 
 
@@ -421,6 +446,7 @@
     public void cleanup() {
         unregisterSensors();
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
+        mStatusBarStateController.removeCallback(mStatusBarStateListener);
     }
 
     static void logDebug(String msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 6ff1bbc..a67f6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.controller
 
+import android.app.ActivityManager
 import android.content.ComponentName
 import android.content.Context
 import android.os.IBinder
@@ -50,7 +51,7 @@
 
     private val refreshing = AtomicBoolean(false)
 
-    private var currentUser = context.user
+    private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
 
     override val currentUserId: Int
         get() = currentUser.identifier
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index bb665fe..3b06ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.controller
 
+import android.app.ActivityManager
 import android.app.PendingIntent
 import android.content.BroadcastReceiver
 import android.content.ComponentName
@@ -78,16 +79,16 @@
 
     private var userChanging: Boolean = true
 
-    private val contentResolver: ContentResolver
-        get() = context.contentResolver
-    override var available = Settings.Secure.getInt(
-            contentResolver, CONTROLS_AVAILABLE, DEFAULT_ENABLED) != 0
-        private set
-
-    private var currentUser = context.user
+    private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
     override val currentUserId
         get() = currentUser.identifier
 
+    private val contentResolver: ContentResolver
+        get() = context.contentResolver
+    override var available = Settings.Secure.getIntForUser(
+            contentResolver, CONTROLS_AVAILABLE, DEFAULT_ENABLED, currentUserId) != 0
+        private set
+
     private val persistenceWrapper = optionalWrapper.orElseGet {
         ControlsFavoritePersistenceWrapper(
                 Environment.buildPath(
@@ -106,7 +107,7 @@
                 userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME)
         persistenceWrapper.changeFile(fileName)
         available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
-                /* default */ DEFAULT_ENABLED, newUser.identifier) != 0
+                DEFAULT_ENABLED, newUser.identifier) != 0
         synchronized(currentFavorites) {
             currentFavorites.clear()
         }
@@ -142,7 +143,7 @@
                 return
             }
             available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
-                    /* default */ DEFAULT_ENABLED, currentUserId) != 0
+                    DEFAULT_ENABLED, currentUserId) != 0
             synchronized(currentFavorites) {
                 currentFavorites.clear()
             }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
new file mode 100644
index 0000000..c053517
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.text.TextUtils
+import android.util.ArrayMap
+import com.android.systemui.controls.ControlStatus
+import com.android.systemui.controls.controller.ControlInfo
+
+/**
+ * This model is used to show all controls separated by zones.
+ *
+ * The model will sort the controls and zones in the following manner:
+ *  * The zones will be sorted in a first seen basis
+ *  * The controls in each zone will be sorted in a first seen basis.
+ *
+ * @property controls List of all controls as returned by loading
+ * @property initialFavoriteIds sorted ids of favorite controls
+ * @property noZoneString text to use as header for all controls that have blank or `null` zone.
+ */
+class AllModel(
+    private val controls: List<ControlStatus>,
+    initialFavoriteIds: List<String>,
+    private val emptyZoneString: CharSequence
+) : ControlsModel {
+
+    override val favorites: List<ControlInfo.Builder>
+        get() = favoriteIds.mapNotNull { id ->
+            val control = controls.firstOrNull { it.control.controlId == id }?.control
+            control?.let {
+                ControlInfo.Builder().apply {
+                    controlId = it.controlId
+                    controlTitle = it.title
+                    deviceType = it.deviceType
+                }
+            }
+        }
+
+    private val favoriteIds = initialFavoriteIds.toMutableList()
+
+    override val elements: List<ElementWrapper> = createWrappers(controls)
+
+    override fun changeFavoriteStatus(controlId: String, favorite: Boolean) {
+        if (favorite) {
+            favoriteIds.add(controlId)
+        } else {
+            favoriteIds.remove(controlId)
+        }
+    }
+
+    private fun createWrappers(list: List<ControlStatus>): List<ElementWrapper> {
+        val map = list.groupByTo(OrderedMap(ArrayMap<CharSequence, MutableList<ControlStatus>>())) {
+            it.control.zone ?: ""
+        }
+        val output = mutableListOf<ElementWrapper>()
+        var emptyZoneValues: Sequence<ControlWrapper>? = null
+        for (zoneName in map.orderedKeys) {
+            val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) }
+            if (TextUtils.isEmpty(zoneName)) {
+                emptyZoneValues = values
+            } else {
+                output.add(ZoneNameWrapper(zoneName))
+                output.addAll(values)
+            }
+        }
+        // Add controls with empty zone at the end
+        if (emptyZoneValues != null) {
+            if (map.size != 1) {
+                output.add(ZoneNameWrapper(emptyZoneString))
+            }
+            output.addAll(emptyZoneValues)
+        }
+        return output
+    }
+
+    private class OrderedMap<K, V>(private val map: MutableMap<K, V>) : MutableMap<K, V> by map {
+
+        val orderedKeys = mutableListOf<K>()
+
+        override fun put(key: K, value: V): V? {
+            if (key !in map) {
+                orderedKeys.add(key)
+            }
+            return map.put(key, value)
+        }
+
+        override fun clear() {
+            orderedKeys.clear()
+            map.clear()
+        }
+
+        override fun remove(key: K): V? {
+            val removed = map.remove(key)
+            if (removed != null) {
+                orderedKeys.remove(key)
+            }
+            return removed
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index ac5e089..25ebc65 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -116,6 +116,10 @@
 
     fun renderFavoritesForComponent(component: ComponentName): String {
         val qty = favoriteFunction(component)
-        return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty)
+        if (qty != 0) {
+            return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty)
+        } else {
+            return ""
+        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index d3cabe6..0870a4d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -42,8 +42,7 @@
  * @param onlyFavorites set to true to only display favorites instead of all controls
  */
 class ControlAdapter(
-    private val layoutInflater: LayoutInflater,
-    private val onlyFavorites: Boolean = false
+    private val layoutInflater: LayoutInflater
 ) : RecyclerView.Adapter<Holder>() {
 
     companion object {
@@ -57,22 +56,21 @@
         }
     }
 
-    var modelList: List<ElementWrapper> = emptyList()
-    private var favoritesModel: FavoriteModel? = null
+    private var model: ControlsModel? = null
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
         return when (viewType) {
             TYPE_CONTROL -> {
                 ControlHolder(
-                        layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
-                            layoutParams.apply {
-                                width = ViewGroup.LayoutParams.MATCH_PARENT
-                            }
-                            elevation = 15f
-                        },
-                        { id, favorite ->
-                            favoritesModel?.changeFavoriteStatus(id, favorite)
-                        })
+                    layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
+                        layoutParams.apply {
+                            width = ViewGroup.LayoutParams.MATCH_PARENT
+                        }
+                        elevation = 15f
+                    }
+                ) { id, favorite ->
+                    model?.changeFavoriteStatus(id, favorite)
+                }
             }
             TYPE_ZONE -> {
                 ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false))
@@ -81,27 +79,26 @@
         }
     }
 
-    fun changeFavoritesModel(favoritesModel: FavoriteModel) {
-        this.favoritesModel = favoritesModel
-        if (onlyFavorites) {
-            modelList = favoritesModel.favorites
-        } else {
-            modelList = favoritesModel.all
-        }
+    fun changeModel(model: ControlsModel) {
+        this.model = model
         notifyDataSetChanged()
     }
 
-    override fun getItemCount() = modelList.size
+    override fun getItemCount() = model?.elements?.size ?: 0
 
     override fun onBindViewHolder(holder: Holder, index: Int) {
-        holder.bindData(modelList[index])
+        model?.let {
+            holder.bindData(it.elements[index])
+        }
     }
 
     override fun getItemViewType(position: Int): Int {
-        return when (modelList[position]) {
-            is ZoneNameWrapper -> TYPE_ZONE
-            is ControlWrapper -> TYPE_CONTROL
-        }
+        model?.let {
+            return when (it.elements.get(position)) {
+                is ZoneNameWrapper -> TYPE_ZONE
+                is ControlWrapper -> TYPE_CONTROL
+            }
+        } ?: throw IllegalStateException("Getting item type for null model")
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index af4a977..2c014498 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -26,11 +26,9 @@
 import android.widget.Button
 import android.widget.TextView
 import androidx.recyclerview.widget.GridLayoutManager
-import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.controls.controller.ControlInfo
 import com.android.systemui.controls.controller.ControlsControllerImpl
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.settings.CurrentUserTracker
@@ -51,33 +49,10 @@
 
     private lateinit var recyclerViewAll: RecyclerView
     private lateinit var adapterAll: ControlAdapter
-    private lateinit var recyclerViewFavorites: RecyclerView
-    private lateinit var adapterFavorites: ControlAdapter
-    private lateinit var errorText: TextView
+    private lateinit var statusText: TextView
+    private var model: ControlsModel? = null
     private var component: ComponentName? = null
 
-    private var currentModel: FavoriteModel? = null
-    private var itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(
-            /* dragDirs */ ItemTouchHelper.UP
-                    or ItemTouchHelper.DOWN
-                    or ItemTouchHelper.LEFT
-                    or ItemTouchHelper.RIGHT,
-            /* swipeDirs */0
-    ) {
-        override fun onMove(
-            recyclerView: RecyclerView,
-            viewHolder: RecyclerView.ViewHolder,
-            target: RecyclerView.ViewHolder
-        ): Boolean {
-            return currentModel?.onMoveItem(
-                    viewHolder.layoutPosition, target.layoutPosition) != null
-        }
-
-        override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
-
-        override fun isItemViewSwipeEnabled() = false
-    }
-
     private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
         private val startingUser = controller.currentUserId
 
@@ -89,6 +64,10 @@
         }
     }
 
+    override fun onBackPressed() {
+        finish()
+    }
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.controls_management)
@@ -99,21 +78,27 @@
 
         val app = intent.getCharSequenceExtra(EXTRA_APP)
         component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
-        errorText = requireViewById(R.id.error_message)
+        statusText = requireViewById(R.id.status_message)
 
-        setUpRecyclerViews()
+        setUpRecyclerView()
 
         requireViewById<TextView>(R.id.title).text = app?.let { it }
                 ?: resources.getText(R.string.controls_favorite_default_title)
         requireViewById<TextView>(R.id.subtitle).text =
                 resources.getText(R.string.controls_favorite_subtitle)
 
+        requireViewById<Button>(R.id.other_apps).apply {
+            visibility = View.VISIBLE
+            setOnClickListener {
+                this@ControlsFavoritingActivity.onBackPressed()
+            }
+        }
+
         requireViewById<Button>(R.id.done).setOnClickListener {
             if (component == null) return@setOnClickListener
-            val favoritesForStorage = currentModel?.favorites?.map {
-                with(it.controlStatus.control) {
-                    ControlInfo(component!!, controlId, title, deviceType)
-                }
+            val favoritesForStorage = model?.favorites?.map {
+                it.componentName = component!!
+                it.build()
             }
             if (favoritesForStorage != null) {
                 controller.replaceFavoritesForComponent(component!!, favoritesForStorage)
@@ -122,20 +107,22 @@
         }
 
         component?.let {
+            statusText.text = resources.getText(com.android.internal.R.string.loading)
             controller.loadForComponent(it, Consumer { data ->
                 val allControls = data.allControls
                 val favoriteKeys = data.favoritesIds
                 val error = data.errorOnLoad
                 executor.execute {
-                    val favoriteModel = FavoriteModel(
-                        allControls,
-                        favoriteKeys,
-                        allAdapter = adapterAll,
-                        favoritesAdapter = adapterFavorites)
-                    adapterAll.changeFavoritesModel(favoriteModel)
-                    adapterFavorites.changeFavoritesModel(favoriteModel)
-                    currentModel = favoriteModel
-                    errorText.visibility = if (error) View.VISIBLE else View.GONE
+                    val emptyZoneString = resources.getText(
+                            R.string.controls_favorite_other_zone_header)
+                    val model = AllModel(allControls, favoriteKeys, emptyZoneString)
+                    adapterAll.changeModel(model)
+                    this.model = model
+                    if (error) {
+                        statusText.text = resources.getText(R.string.controls_favorite_load_error)
+                    } else {
+                        statusText.visibility = View.GONE
+                    }
                 }
             })
         }
@@ -143,7 +130,7 @@
         currentUserTracker.startTracking()
     }
 
-    private fun setUpRecyclerViews() {
+    private fun setUpRecyclerView() {
         val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
         val itemDecorator = MarginItemDecorator(margin, margin)
         val layoutInflater = LayoutInflater.from(applicationContext)
@@ -156,14 +143,6 @@
             }
             addItemDecoration(itemDecorator)
         }
-
-        adapterFavorites = ControlAdapter(layoutInflater, true)
-        recyclerViewFavorites = requireViewById<RecyclerView>(R.id.listFavorites).apply {
-            layoutManager = GridLayoutManager(applicationContext, 2)
-            adapter = adapterFavorites
-            addItemDecoration(itemDecorator)
-        }
-        ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerViewFavorites)
     }
 
     override fun onDestroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 882382c..53f3019 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.management
 
+import android.app.ActivityManager
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.ServiceInfo
@@ -72,7 +73,7 @@
 
     private var availableServices = emptyList<ServiceInfo>()
 
-    override var currentUserId = context.userId
+    override var currentUserId = ActivityManager.getCurrentUser()
         private set
 
     private val serviceListingCallback = ServiceListing.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
new file mode 100644
index 0000000..a995a2e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import com.android.systemui.controls.ControlStatus
+import com.android.systemui.controls.controller.ControlInfo
+
+/**
+ * Model for using with [ControlAdapter].
+ *
+ * Implementations of this interface provide different views of the controls to show.
+ */
+interface ControlsModel {
+
+    /**
+     * List of favorites (builders) in order.
+     *
+     * This should be obtained prior to storing the favorites using
+     * [ControlsController.replaceFavoritesForComponent].
+     */
+    val favorites: List<ControlInfo.Builder>
+
+    /**
+     * List of all the elements to display by the corresponding [RecyclerView].
+     */
+    val elements: List<ElementWrapper>
+
+    /**
+     * Change the favorite status of a particular control.
+     */
+    fun changeFavoriteStatus(controlId: String, favorite: Boolean) {}
+
+    /**
+     * Move an item (in elements) from one position to another.
+     */
+    fun onMoveItem(from: Int, to: Int) {}
+}
+
+/**
+ * Wrapper classes for the different types of elements shown in the [RecyclerView]s in
+ * [ControlAdapter].
+ */
+sealed class ElementWrapper
+data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper()
+data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index ad4bdef..098caf6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -21,6 +21,7 @@
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.ViewStub
+import android.widget.Button
 import android.widget.TextView
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
@@ -86,6 +87,10 @@
         requireViewById<TextView>(R.id.subtitle).text =
                 resources.getText(R.string.controls_providers_subtitle)
 
+        requireViewById<Button>(R.id.done).setOnClickListener {
+            this@ControlsProviderSelectorActivity.finishAffinity()
+        }
+
         currentUserTracker.startTracking()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt
index 6bade0a..5c51e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt
@@ -142,12 +142,4 @@
         else if (p0 != null && p1 == null) return 1
         return p0.toString().compareTo(p1.toString())
     }
-}
-
-/**
- * Wrapper classes for the different types of elements shown in the [RecyclerView]s in
- * [ControlsFavoritingActivity].
- */
-sealed class ElementWrapper
-data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper()
-data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 7c0033c..024378d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -20,6 +20,7 @@
 
 import android.app.INotificationManager;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
@@ -34,6 +35,7 @@
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.Prefs;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
@@ -79,6 +81,13 @@
 
     /** */
     @Provides
+    @Main
+    public SharedPreferences provideSharePreferences(Context context) {
+        return Prefs.get(context);
+    }
+
+    /** */
+    @Provides
     public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
         return new AmbientDisplayConfiguration(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 3aa14a3..352ee33 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -209,6 +209,7 @@
 
     @Provides
     @Singleton
+    @Nullable
     static TelecomManager provideTelecomManager(Context context) {
         return context.getSystemService(TelecomManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 5da02dc..24f505d 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -206,7 +206,7 @@
             ConfigurationController configurationController, ActivityStarter activityStarter,
             KeyguardStateController keyguardStateController, UserManager userManager,
             TrustManager trustManager, IActivityManager iActivityManager,
-            TelecomManager telecomManager, MetricsLogger metricsLogger,
+            @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
             BlurUtils blurUtils, SysuiColorExtractor colorExtractor,
             IStatusBarService statusBarService,
             NotificationShadeWindowController notificationShadeWindowController,
@@ -568,13 +568,16 @@
         @Override
         public void onPress() {
             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);
-            intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
-                    EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            if (mTelecomManager != null) {
+                Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(
+                        null /* number */);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                        EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
+                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 79a25b2..3b855db 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -67,6 +67,8 @@
 
     // Allow dragging the PIP to a location to close it
     private final boolean mEnableDismissDragToEdge;
+    // Allow PIP to resize to a slightly bigger state upon touch
+    private final boolean mEnableResize;
     private final Context mContext;
     private final IActivityManager mActivityManager;
     private final PipBoundsHandler mPipBoundsHandler;
@@ -188,6 +190,7 @@
         mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
 
         mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
+        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
 
         // Register the listener for input consumer touch events
         inputConsumerController.setInputListener(this::handleTouchEvent);
@@ -297,7 +300,7 @@
             } else {
                 final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP
                         * mContext.getResources().getDisplayMetrics().density;
-                final Rect toMovementBounds = mMenuState == MENU_STATE_FULL
+                final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu()
                         ? new Rect(expandedMovementBounds)
                         : new Rect(normalMovementBounds);
                 final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
@@ -691,11 +694,12 @@
     };
 
     /**
-     * Updates the current movement bounds based on whether the menu is currently visible.
+     * Updates the current movement bounds based on whether the menu is currently visible and
+     * resized.
      */
     private void updateMovementBounds(int menuState) {
         boolean isMenuExpanded = menuState == MENU_STATE_FULL;
-        mMovementBounds = isMenuExpanded
+        mMovementBounds = isMenuExpanded && willResizeMenu()
                 ? mExpandedMovementBounds
                 : mNormalMovementBounds;
         mPipBoundsHandler.setMinEdgeSize(
@@ -715,8 +719,11 @@
      * @return whether the menu will resize as a part of showing the full menu.
      */
     private boolean willResizeMenu() {
-        return mExpandedBounds.width() != mNormalBounds.width() ||
-                mExpandedBounds.height() != mNormalBounds.height();
+        if (!mEnableResize) {
+            return false;
+        }
+        return mExpandedBounds.width() != mNormalBounds.width()
+                || mExpandedBounds.height() != mNormalBounds.height();
     }
 
     public void dump(PrintWriter pw, String prefix) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ebf45a6..9f7b84a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -53,6 +53,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -79,6 +80,7 @@
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
     private final ActivityStarter mActivityStarter;
+    private final SharedPreferences mSharedPreferences;
     private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mListening;
@@ -87,10 +89,12 @@
 
     @Inject
     public DndTile(QSHost host, ZenModeController zenModeController,
-            ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher) {
+            ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher,
+            @Main SharedPreferences sharedPreferences) {
         super(host);
         mController = zenModeController;
         mActivityStarter = activityStarter;
+        mSharedPreferences = sharedPreferences;
         mDetailAdapter = new DndDetailAdapter();
         mBroadcastDispatcher = broadcastDispatcher;
         broadcastDispatcher.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
@@ -111,16 +115,16 @@
         Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
     }
 
-    public static boolean isVisible(Context context) {
-        return Prefs.getBoolean(context, Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */);
+    public static boolean isVisible(SharedPreferences prefs) {
+        return prefs.getBoolean(Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */);
     }
 
     public static void setCombinedIcon(Context context, boolean combined) {
         Prefs.putBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, combined);
     }
 
-    public static boolean isCombinedIcon(Context context) {
-        return Prefs.getBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON,
+    public static boolean isCombinedIcon(SharedPreferences sharedPreferences) {
+        return sharedPreferences.getBoolean(Prefs.Key.DND_TILE_COMBINED_ICON,
                 false /* defaultValue */);
     }
 
@@ -301,7 +305,7 @@
 
     @Override
     public boolean isAvailable() {
-        return isVisible(mContext);
+        return isVisible(mSharedPreferences);
     }
 
     private final OnSharedPreferenceChangeListener mPrefListener
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 2557226..5dcb4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -16,9 +16,9 @@
 
 package com.android.systemui.qs.tiles;
 
-import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
@@ -81,11 +81,11 @@
     }
 
     public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
-            Context context) {
+            Resources resources) {
         int lockOrientation = controller.getRotationLockOrientation();
         if (lockOrientation == Configuration.ORIENTATION_UNDEFINED) {
             // Freely rotating device; use current rotation
-            return context.getResources().getConfiguration().orientation
+            return resources.getConfiguration().orientation
                     != Configuration.ORIENTATION_LANDSCAPE;
         } else {
             return lockOrientation != Configuration.ORIENTATION_LANDSCAPE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 39bfd5a..f169501 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -206,7 +206,7 @@
             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
             state.label = removeDoubleQuotes(cb.ssid);
         } else if (wifiNotConnected) {
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
+            state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else {
             state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index f06cd54..3afd5dc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -514,12 +514,17 @@
                         1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct));
                 mScreenshotView.setScaleX(scale);
                 mScreenshotView.setScaleY(scale);
+            } else {
+                mScreenshotView.setScaleX(cornerScale);
+                mScreenshotView.setScaleY(cornerScale);
             }
 
             if (t < xPositionPct) {
                 float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
                         mFastOutSlowIn.getInterpolation(t / xPositionPct));
                 mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f);
+            } else {
+                mScreenshotView.setX(finalPos.x - width * mScreenshotView.getScaleX() / 2f);
             }
             float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
                     mFastOutSlowIn.getInterpolation(t));
@@ -544,6 +549,10 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
+                mScreenshotView.setScaleX(cornerScale);
+                mScreenshotView.setScaleY(cornerScale);
+                mScreenshotView.setX(finalPos.x - height * cornerScale / 2f);
+                mScreenshotView.setY(finalPos.y - height * cornerScale / 2f);
                 Rect bounds = new Rect();
                 mScreenshotView.getBoundsOnScreen(bounds);
                 mDismissButton.setX(bounds.right - mDismissButtonSize / 2f);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 56cdff4..27b799b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -401,6 +401,7 @@
                 return;
             }
             mMinimized = minimized;
+            WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized);
             mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
             updateTouchable();
         });
@@ -504,6 +505,7 @@
         final boolean wasMinimized = mMinimized;
         mMinimized = true;
         setHomeStackResizable(mSplits.mSecondary.isResizable());
+        WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */);
         if (!inSplitMode()) {
             // Wasn't in split-mode yet, so enter now.
             if (DEBUG) {
@@ -521,6 +523,9 @@
     }
 
     void ensureNormalSplit() {
+        if (mMinimized) {
+            WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */);
+        }
         if (!inSplitMode()) {
             // Wasn't in split-mode, so enter now.
             if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 7685733..167c33a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -292,10 +292,23 @@
             for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
                 wct.setBounds(freeHomeAndRecents.get(i).token, null);
             }
+            // Reset focusable to true
+            wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
             ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
                     null /* organizer */);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to remove stack: " + e);
         }
     }
+
+    static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) {
+        try {
+            WindowContainerTransaction wct = new WindowContainerTransaction();
+            wct.setFocusable(splits.mPrimary.token, focusable);
+            ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
+                    null /* organizer */);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error setting focusability: " + e);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 97755fc..004b56b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -807,7 +807,7 @@
         // TODO: Move inflation logic out of this call
         if (mIsChildInGroup != isChildInGroup) {
             mIsChildInGroup = isChildInGroup;
-            if (mIsLowPriority) {
+            if (!isRemoved() && mIsLowPriority) {
                 RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
                 params.setUseLowPriority(mIsLowPriority);
                 mRowContentBindStage.requestRebind(mEntry, null /* callback */);
@@ -1576,13 +1576,15 @@
         // TODO: Move inflation logic out of this call and remove this method
         if (mNeedsRedaction != needsRedaction) {
             mNeedsRedaction = needsRedaction;
-            RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
-            if (needsRedaction) {
-                params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
-            } else {
-                params.freeContentViews(FLAG_CONTENT_VIEW_PUBLIC);
+            if (!isRemoved()) {
+                RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry);
+                if (needsRedaction) {
+                    params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
+                } else {
+                    params.freeContentViews(FLAG_CONTENT_VIEW_PUBLIC);
+                }
+                mRowContentBindStage.requestRebind(mEntry, null /* callback */);
             }
-            mRowContentBindStage.requestRebind(mEntry, null /* callback */);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 60eda06..bab7840 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -20,6 +20,7 @@
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
 import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS;
@@ -218,7 +219,7 @@
         // TODO: consider querying this earlier in the notification pipeline and passing it in
         LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
                 .setPackage(mPackageName)
-                .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
+                .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED)
                 .setShortcutIds(Arrays.asList(mConversationId));
         List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser());
         if (shortcuts != null && !shortcuts.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 8729e04..f38d416 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -44,8 +44,9 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -91,6 +92,7 @@
     private boolean mExpandAnimationRunning;
     private NotificationStackScrollLayout mStackScrollLayout;
     private PhoneStatusBarView mStatusBarView;
+    private PhoneStatusBarTransitions mBarTransitions;
     private StatusBar mService;
     private DragDownHelper mDragDownHelper;
     private boolean mDoubleTapEnabled;
@@ -98,6 +100,7 @@
     private boolean mExpandingBelowNotch;
     private final DockManager mDockManager;
     private final NotificationPanelViewController mNotificationPanelViewController;
+    private final SuperStatusBarViewFactory mStatusBarViewFactory;
 
     // Used for determining view / touch intersection
     private int[] mTempLocation = new int[2];
@@ -124,8 +127,9 @@
             ShadeController shadeController,
             DockManager dockManager,
             @Nullable NotificationShadeWindowBlurController blurController,
-            NotificationShadeWindowView statusBarWindowView,
-            NotificationPanelViewController notificationPanelViewController) {
+            NotificationShadeWindowView notificationShadeWindowView,
+            NotificationPanelViewController notificationPanelViewController,
+            SuperStatusBarViewFactory statusBarViewFactory) {
         mInjectionInflationController = injectionInflationController;
         mCoordinator = coordinator;
         mPulseExpansionHandler = pulseExpansionHandler;
@@ -141,11 +145,12 @@
         mDozeLog = dozeLog;
         mDozeParameters = dozeParameters;
         mCommandQueue = commandQueue;
-        mView = statusBarWindowView;
+        mView = notificationShadeWindowView;
         mShadeController = shadeController;
         mDockManager = dockManager;
         mNotificationPanelViewController = notificationPanelViewController;
         mBlurController = blurController;
+        mStatusBarViewFactory = statusBarViewFactory;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror);
@@ -440,8 +445,18 @@
         }
     }
 
+    public PhoneStatusBarTransitions getBarTransitions() {
+        return mBarTransitions;
+    }
+
     public void setStatusBarView(PhoneStatusBarView statusBarView) {
         mStatusBarView = statusBarView;
+        if (statusBarView != null && mStatusBarViewFactory != null) {
+            mBarTransitions = new PhoneStatusBarTransitions(
+                    statusBarView,
+                    mStatusBarViewFactory.getStatusBarWindowView()
+                            .findViewById(R.id.status_bar_container));
+        }
     }
 
     public void setService(StatusBar statusBar) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 1ab36c5..14af466 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -16,15 +16,18 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.ActivityManager;
+import android.annotation.Nullable;
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
 import android.app.AlarmManager.AlarmClockInfo;
+import android.app.IActivityManager;
 import android.app.SynchronousUserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -33,13 +36,13 @@
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
 import android.telecom.TelecomManager;
-import android.telephony.TelephonyManager;
 import android.text.format.DateFormat;
 import android.util.Log;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
@@ -61,10 +64,13 @@
 import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.time.DateFormatUtil;
 
 import java.util.Locale;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 /**
  * This class contains all of the policy about which icons are installed in the status bar at boot
  * time. It goes through the normal API for icons, even though it probably strictly doesn't need to.
@@ -82,7 +88,7 @@
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final int LOCATION_STATUS_ICON_ID =
+    static final int LOCATION_STATUS_ICON_ID =
             com.android.internal.R.drawable.perm_group_location;
 
     private final String mSlotCast;
@@ -97,20 +103,26 @@
     private final String mSlotHeadset;
     private final String mSlotDataSaver;
     private final String mSlotLocation;
-    private final String mSlotMicrophone;
-    private final String mSlotCamera;
     private final String mSlotSensorsOff;
     private final String mSlotScreenRecord;
+    private final int mDisplayId;
+    private final SharedPreferences mSharedPreferences;
+    private final DateFormatUtil mDateFormatUtil;
+    private final TelecomManager mTelecomManager;
+    private final AudioManager mAudioManager;
 
-    private final Context mContext;
     private final Handler mHandler = new Handler();
     private final CastController mCast;
     private final HotspotController mHotspot;
     private final NextAlarmController mNextAlarmController;
     private final AlarmManager mAlarmManager;
     private final UserInfoController mUserInfoController;
+    private final IActivityManager mIActivityManager;
     private final UserManager mUserManager;
     private final StatusBarIconController mIconController;
+    private final CommandQueue mCommandQueue;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+    private final Resources mResources;
     private final RotationLockController mRotationLockController;
     private final DataSaverController mDataSaver;
     private final ZenModeController mZenController;
@@ -121,10 +133,6 @@
     private final SensorPrivacyController mSensorPrivacyController;
     private final RecordingController mRecordingController;
 
-    // Assume it's all good unless we hear otherwise.  We don't always seem
-    // to get broadcasts that it *is* there.
-    int mSimState = TelephonyManager.SIM_STATE_READY;
-
     private boolean mZenVisible;
     private boolean mVolumeVisible;
     private boolean mCurrentUserSetup;
@@ -134,47 +142,70 @@
     private BluetoothController mBluetooth;
     private AlarmManager.AlarmClockInfo mNextAlarm;
 
-    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
+    @Inject
+    public PhoneStatusBarPolicy(StatusBarIconController iconController,
             CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher,
-            @UiBackground Executor uiBgExecutor) {
-        mContext = context;
+            @UiBackground Executor uiBgExecutor, @Main Resources resources,
+            CastController castController, HotspotController hotspotController,
+            BluetoothController bluetoothController, NextAlarmController nextAlarmController,
+            UserInfoController userInfoController, RotationLockController rotationLockController,
+            DataSaverController dataSaverController, ZenModeController zenModeController,
+            DeviceProvisionedController deviceProvisionedController,
+            KeyguardStateController keyguardStateController,
+            LocationController locationController,
+            SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager,
+            AlarmManager alarmManager, UserManager userManager, AudioManager audioManager,
+            RecordingController recordingController,
+            @Nullable TelecomManager telecomManager, @DisplayId int displayId,
+            @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil) {
         mIconController = iconController;
-        mCast = Dependency.get(CastController.class);
-        mHotspot = Dependency.get(HotspotController.class);
-        mBluetooth = Dependency.get(BluetoothController.class);
-        mNextAlarmController = Dependency.get(NextAlarmController.class);
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        mUserInfoController = Dependency.get(UserInfoController.class);
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mRotationLockController = Dependency.get(RotationLockController.class);
-        mDataSaver = Dependency.get(DataSaverController.class);
-        mZenController = Dependency.get(ZenModeController.class);
-        mProvisionedController = Dependency.get(DeviceProvisionedController.class);
-        mKeyguardStateController = Dependency.get(KeyguardStateController.class);
-        mLocationController = Dependency.get(LocationController.class);
-        mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
-        mRecordingController = Dependency.get(RecordingController.class);
+        mCommandQueue = commandQueue;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mResources = resources;
+        mCast = castController;
+        mHotspot = hotspotController;
+        mBluetooth = bluetoothController;
+        mNextAlarmController = nextAlarmController;
+        mAlarmManager = alarmManager;
+        mUserInfoController = userInfoController;
+        mIActivityManager = iActivityManager;
+        mUserManager = userManager;
+        mRotationLockController = rotationLockController;
+        mDataSaver = dataSaverController;
+        mZenController = zenModeController;
+        mProvisionedController = deviceProvisionedController;
+        mKeyguardStateController = keyguardStateController;
+        mLocationController = locationController;
+        mSensorPrivacyController = sensorPrivacyController;
+        mRecordingController = recordingController;
         mUiBgExecutor = uiBgExecutor;
+        mAudioManager = audioManager;
+        mTelecomManager = telecomManager;
 
-        mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
-        mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
-        mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);
-        mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);
-        mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);
-        mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);
-        mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);
-        mSlotManagedProfile = context.getString(
+        mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
+        mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot);
+        mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth);
+        mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty);
+        mSlotZen = resources.getString(com.android.internal.R.string.status_bar_zen);
+        mSlotVolume = resources.getString(com.android.internal.R.string.status_bar_volume);
+        mSlotAlarmClock = resources.getString(com.android.internal.R.string.status_bar_alarm_clock);
+        mSlotManagedProfile = resources.getString(
                 com.android.internal.R.string.status_bar_managed_profile);
-        mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);
-        mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
-        mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
-        mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);
-        mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone);
-        mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera);
-        mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off);
-        mSlotScreenRecord = context.getString(
+        mSlotRotate = resources.getString(com.android.internal.R.string.status_bar_rotate);
+        mSlotHeadset = resources.getString(com.android.internal.R.string.status_bar_headset);
+        mSlotDataSaver = resources.getString(com.android.internal.R.string.status_bar_data_saver);
+        mSlotLocation = resources.getString(com.android.internal.R.string.status_bar_location);
+        mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off);
+        mSlotScreenRecord = resources.getString(
                 com.android.internal.R.string.status_bar_screen_record);
 
+        mDisplayId = displayId;
+        mSharedPreferences = sharedPreferences;
+        mDateFormatUtil = dateFormatUtil;
+    }
+
+    /** Initialize the object after construction. */
+    public void init() {
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
@@ -185,11 +216,11 @@
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        broadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler);
+        mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler);
 
         // listen for user / profile change.
         try {
-            ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
+            mIActivityManager.registerUserSwitchObserver(mUserSwitchListener, TAG);
         } catch (RemoteException e) {
             // Ignore
         }
@@ -219,26 +250,26 @@
 
         // hotspot
         mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
-                mContext.getString(R.string.accessibility_status_bar_hotspot));
+                mResources.getString(R.string.accessibility_status_bar_hotspot));
         mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
 
         // managed profile
         mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
-                mContext.getString(R.string.accessibility_managed_profile));
+                mResources.getString(R.string.accessibility_managed_profile));
         mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
 
         // data saver
         mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
-                context.getString(R.string.accessibility_data_saver_on));
+                mResources.getString(R.string.accessibility_data_saver_on));
         mIconController.setIconVisibility(mSlotDataSaver, false);
 
         mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
-                mContext.getString(R.string.accessibility_location_active));
+                mResources.getString(R.string.accessibility_location_active));
         mIconController.setIconVisibility(mSlotLocation, false);
 
         // sensors off
         mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off,
-                mContext.getString(R.string.accessibility_sensors_off_active));
+                mResources.getString(R.string.accessibility_sensors_off_active));
         mIconController.setIconVisibility(mSlotSensorsOff,
                 mSensorPrivacyController.isSensorPrivacyEnabled());
 
@@ -259,7 +290,7 @@
         mLocationController.addCallback(this);
         mRecordingController.addCallback(this);
 
-        commandQueue.addCallback(this);
+        mCommandQueue.addCallback(this);
     }
 
     @Override
@@ -284,51 +315,17 @@
 
     private String buildAlarmContentDescription() {
         if (mNextAlarm == null) {
-            return mContext.getString(R.string.status_bar_alarm);
+            return mResources.getString(R.string.status_bar_alarm);
         }
-        return formatNextAlarm(mNextAlarm, mContext);
-    }
 
-    private static String formatNextAlarm(AlarmManager.AlarmClockInfo info, Context context) {
-        if (info == null) {
-            return "";
-        }
-        String skeleton = DateFormat.is24HourFormat(
-                context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
+        String skeleton = mDateFormatUtil.is24HourFormat() ? "EHm" : "Ehma";
         String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
-        String dateString = DateFormat.format(pattern, info.getTriggerTime()).toString();
+        String dateString = DateFormat.format(pattern, mNextAlarm.getTriggerTime()).toString();
 
-        return context.getString(R.string.accessibility_quick_settings_alarm, dateString);
-    }
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
-        if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
-            mSimState = TelephonyManager.SIM_STATE_READY;
-        } else if (Intent.SIM_STATE_CARD_IO_ERROR.equals(stateExtra)) {
-            mSimState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
-        } else if (Intent.SIM_STATE_CARD_RESTRICTED.equals(stateExtra)) {
-            mSimState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
-        } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
-            mSimState = TelephonyManager.SIM_STATE_READY;
-        } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
-            final String lockedReason =
-                    intent.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
-            if (Intent.SIM_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED;
-            } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED;
-            } else {
-                mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
-        }
+        return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString);
     }
 
     private final void updateVolumeZen() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
         boolean zenVisible = false;
         int zenIconId = 0;
         String zenDescription = null;
@@ -338,29 +335,29 @@
         String volumeDescription = null;
         int zen = mZenController.getZen();
 
-        if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
+        if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) {
             zenVisible = zen != Global.ZEN_MODE_OFF;
             zenIconId = R.drawable.stat_sys_dnd;
-            zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+            zenDescription = mResources.getString(R.string.quick_settings_dnd_label);
         } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_dnd;
-            zenDescription = mContext.getString(R.string.interruption_level_none);
+            zenDescription = mResources.getString(R.string.interruption_level_none);
         } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_dnd;
-            zenDescription = mContext.getString(R.string.interruption_level_priority);
+            zenDescription = mResources.getString(R.string.interruption_level_priority);
         }
 
         if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) {
-            if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
+            if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
                 volumeVisible = true;
                 volumeIconId = R.drawable.stat_sys_ringer_vibrate;
-                volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
-            } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
+                volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate);
+            } else if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
                 volumeVisible = true;
                 volumeIconId = R.drawable.stat_sys_ringer_silent;
-                volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
+                volumeDescription = mResources.getString(R.string.accessibility_ringer_silent);
             }
         }
 
@@ -395,13 +392,13 @@
     private final void updateBluetooth() {
         int iconId = R.drawable.stat_sys_data_bluetooth_connected;
         String contentDescription =
-                mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
+                mResources.getString(R.string.accessibility_quick_settings_bluetooth_on);
         boolean bluetoothVisible = false;
         if (mBluetooth != null) {
             if (mBluetooth.isBluetoothConnected()
                     && (mBluetooth.isBluetoothAudioActive()
                     || !mBluetooth.isBluetoothAudioProfileOnly())) {
-                contentDescription = mContext.getString(
+                contentDescription = mResources.getString(
                         R.string.accessibility_bluetooth_connected);
                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
             }
@@ -412,12 +409,10 @@
     }
 
     private final void updateTTY() {
-        TelecomManager telecomManager =
-                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-        if (telecomManager == null) {
+        if (mTelecomManager == null) {
             updateTTY(TelecomManager.TTY_MODE_OFF);
         } else {
-            updateTTY(telecomManager.getCurrentTtyMode());
+            updateTTY(mTelecomManager.getCurrentTtyMode());
         }
     }
 
@@ -430,7 +425,7 @@
             // TTY is on
             if (DEBUG) Log.v(TAG, "updateTTY: set TTY on");
             mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode,
-                    mContext.getString(R.string.accessibility_tty_enabled));
+                    mResources.getString(R.string.accessibility_tty_enabled));
             mIconController.setIconVisibility(mSlotTty, true);
         } else {
             // TTY is off
@@ -452,7 +447,7 @@
         mHandler.removeCallbacks(mRemoveCastIconRunnable);
         if (isCasting && !mRecordingController.isRecording()) { // screen record has its own icon
             mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast,
-                    mContext.getString(R.string.accessibility_casting));
+                    mResources.getString(R.string.accessibility_casting));
             mIconController.setIconVisibility(mSlotCast, true);
         } else {
             // don't turn off the screen-record icon for a few seconds, just to make sure the user
@@ -478,7 +473,7 @@
                         showIcon = true;
                         mIconController.setIcon(mSlotManagedProfile,
                                 R.drawable.stat_sys_managed_profile_status,
-                                mContext.getString(R.string.accessibility_managed_profile));
+                                mResources.getString(R.string.accessibility_managed_profile));
                     } else {
                         showIcon = false;
                     }
@@ -545,7 +540,7 @@
     @Override
     public void appTransitionStarting(int displayId, long startTime, long duration,
             boolean forced) {
-        if (mContext.getDisplayId() == displayId) {
+        if (mDisplayId == displayId) {
             updateManagedProfile();
         }
     }
@@ -567,14 +562,14 @@
     @Override
     public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
         boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait(
-                mRotationLockController, mContext);
+                mRotationLockController, mResources);
         if (rotationLocked) {
             if (portrait) {
                 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait,
-                        mContext.getString(R.string.accessibility_rotation_lock_on_portrait));
+                        mResources.getString(R.string.accessibility_rotation_lock_on_portrait));
             } else {
                 mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
-                        mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
+                        mResources.getString(R.string.accessibility_rotation_lock_on_landscape));
             }
             mIconController.setIconVisibility(mSlotRotate, true);
         } else {
@@ -586,7 +581,7 @@
         boolean connected = intent.getIntExtra("state", 0) != 0;
         boolean hasMic = intent.getIntExtra("microphone", 0) != 0;
         if (connected) {
-            String contentDescription = mContext.getString(hasMic
+            String contentDescription = mResources.getString(hasMic
                     ? R.string.accessibility_status_bar_headset
                     : R.string.accessibility_status_bar_headphones);
             mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
@@ -630,7 +625,6 @@
                     if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                         break;
                     }
-                    updateSimState(intent);
                     break;
                 case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:
                     updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index e8bc2f5..2052ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -29,23 +29,21 @@
     private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f;
     private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0;
 
-    private final PhoneStatusBarView mView;
     private final float mIconAlphaWhenOpaque;
 
-    private View mLeftSide, mStatusIcons, mBattery, mClock;
+    private View mLeftSide, mStatusIcons, mBattery;
     private Animator mCurrentAnimation;
 
-    public PhoneStatusBarTransitions(PhoneStatusBarView view) {
-        super(view, R.drawable.status_background);
-        mView = view;
-        final Resources res = mView.getContext().getResources();
+    /**
+     * @param backgroundView view to apply the background drawable
+     */
+    public PhoneStatusBarTransitions(PhoneStatusBarView statusBarView, View backgroundView) {
+        super(backgroundView, R.drawable.status_background);
+        final Resources res = statusBarView.getContext().getResources();
         mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
-    }
-
-    public void init() {
-        mLeftSide = mView.findViewById(R.id.status_bar_left_side);
-        mStatusIcons = mView.findViewById(R.id.statusIcons);
-        mBattery = mView.findViewById(R.id.battery);
+        mLeftSide = statusBarView.findViewById(R.id.status_bar_left_side);
+        mStatusIcons = statusBarView.findViewById(R.id.statusIcons);
+        mBattery = statusBarView.findViewById(R.id.battery);
         applyModeBackground(-1, getMode(), false /*animate*/);
         applyMode(getMode(), false /*animate*/);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index b949e3a..1359f74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -53,7 +53,6 @@
     StatusBar mBar;
 
     boolean mIsFullyOpenedPanel = false;
-    private final PhoneStatusBarTransitions mBarTransitions;
     private ScrimController mScrimController;
     private float mMinFraction;
     private Runnable mHideExpandedRunnable = new Runnable() {
@@ -83,15 +82,9 @@
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mBarTransitions = new PhoneStatusBarTransitions(this);
         mCommandQueue = Dependency.get(CommandQueue.class);
     }
 
-    public BarTransitions getBarTransitions() {
-        return mBarTransitions;
-    }
-
     public void setBar(StatusBar bar) {
         mBar = bar;
     }
@@ -102,7 +95,6 @@
 
     @Override
     public void onFinishInflate() {
-        mBarTransitions.init();
         mBattery = findViewById(R.id.battery);
         mCutoutSpace = findViewById(R.id.cutout_space_view);
         mCenterIconSpace = findViewById(R.id.centered_icon_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 0d3b09a..b620d17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -676,6 +676,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            PhoneStatusBarPolicy phoneStatusBarPolicy,
             DismissCallbackRegistry dismissCallbackRegistry,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
         super(context);
@@ -751,6 +752,7 @@
         mKeyguardDismissUtil = keyguardDismissUtil;
         mExtensionController = extensionController;
         mUserInfoControllerImpl = userInfoControllerImpl;
+        mIconPolicy = phoneStatusBarPolicy;
         mDismissCallbackRegistry = dismissCallbackRegistry;
 
         mBubbleExpandListener =
@@ -875,8 +877,7 @@
         // end old BaseStatusBar.start().
 
         // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCommandQueue,
-                mBroadcastDispatcher, mUiBgExecutor);
+        mIconPolicy.init();
         mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
 
         mKeyguardStateController.addCallback(this);
@@ -2305,13 +2306,14 @@
     }
 
     protected BarTransitions getStatusBarTransitions() {
-        return mStatusBarView.getBarTransitions();
+        return mNotificationShadeWindowViewController.getBarTransitions();
     }
 
     void checkBarModes() {
         if (mDemoMode) return;
-        if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
-                getStatusBarTransitions());
+        if (mNotificationShadeWindowViewController != null) {
+            checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
+        }
         mNavigationBarController.checkNavBarModes(mDisplayId);
         mNoAnimationOnNextBarModeChange = false;
     }
@@ -2329,8 +2331,9 @@
     }
 
     private void finishBarAnimations() {
-        if (mStatusBarView != null) {
-            mStatusBarView.getBarTransitions().finishAnimations();
+        if (mNotificationShadeWindowController != null
+                && mNotificationShadeWindowViewController.getBarTransitions() != null) {
+            mNotificationShadeWindowViewController.getBarTransitions().finishAnimations();
         }
         mNavigationBarController.finishBarAnimations(mDisplayId);
     }
@@ -2396,12 +2399,11 @@
         pw.print("  mDozing="); pw.println(mDozing);
         pw.print("  mWallpaperSupported= "); pw.println(mWallpaperSupported);
 
-        if (mStatusBarView != null) {
-            dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
-        }
         pw.println("  StatusBarWindowView: ");
         if (mNotificationShadeWindowViewController != null) {
             mNotificationShadeWindowViewController.dump(fd, pw, args);
+            dumpBarTransitions(pw, "PhoneStatusBarTransitions",
+                    mNotificationShadeWindowViewController.getBarTransitions());
         }
 
         pw.println("  mMediaManager: ");
@@ -3004,8 +3006,10 @@
                     -1;
             if (barMode != -1) {
                 boolean animate = true;
-                if (mStatusBarView != null) {
-                    mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
+                if (mNotificationShadeWindowController != null
+                        && mNotificationShadeWindowViewController.getBarTransitions() != null) {
+                    mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
+                            barMode, animate);
                 }
                 mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index e64f821..0a4fdc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -79,6 +79,7 @@
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -193,6 +194,7 @@
             KeyguardDismissUtil keyguardDismissUtil,
             ExtensionController extensionController,
             UserInfoControllerImpl userInfoControllerImpl,
+            PhoneStatusBarPolicy phoneStatusBarPolicy,
             DismissCallbackRegistry dismissCallbackRegistry,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
         return new StatusBar(
@@ -269,6 +271,7 @@
                 keyguardDismissUtil,
                 extensionController,
                 userInfoControllerImpl,
+                phoneStatusBarPolicy,
                 dismissCallbackRegistry,
                 statusBarTouchableRegionManager);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index d090404..7d532a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -56,8 +56,9 @@
 
     private int mHotspotState;
     private volatile int mNumConnectedDevices;
-    private volatile boolean mIsTetheringSupported;
-    private volatile boolean mHasTetherableWifiRegexs;
+    // Assume tethering is available until told otherwise
+    private volatile boolean mIsTetheringSupported = true;
+    private volatile boolean mHasTetherableWifiRegexs = true;
     private boolean mWaitingForTerminalState;
 
     private TetheringManager.TetheringEventCallback mTetheringCallback =
@@ -97,6 +98,15 @@
                 new HandlerExecutor(backgroundHandler), mTetheringCallback);
     }
 
+    /**
+     * Whether hotspot is currently supported.
+     *
+     * This will return {@code true} immediately on creation of the controller, but may be updated
+     * later. Callbacks from this controllers will notify if the state changes.
+     *
+     * @return {@code true} if hotspot is supported (or we haven't been told it's not)
+     * @see #addCallback
+     */
     @Override
     public boolean isHotspotSupported() {
         return mIsTetheringSupported && mHasTetherableWifiRegexs
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 8bd0f2c..7c96386 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -88,15 +88,16 @@
         boolean wifiVisible = mCurrentState.enabled
                 && ((mCurrentState.connected && mCurrentState.inetCondition == 1)
                     || !mHasMobileData || visibleWhenEnabled);
-        String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
+        String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null;
         boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
         String contentDescription = getTextIfExists(getContentDescription()).toString();
         if (mCurrentState.inetCondition == 0) {
             contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
         }
         IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
-        IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
-                contentDescription);
+        IconState qsIcon = new IconState(mCurrentState.connected,
+                mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
+                        : getQsCurrentIconId(), contentDescription);
         callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
                 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
                 wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index b5bede4..13ba1a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -40,12 +40,11 @@
  */
 public class ProximitySensor {
     private static final String TAG = "ProxSensor";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Sensor mSensor;
     private final AsyncSensorManager mSensorManager;
-    private final boolean mUsingBrightnessSensor;
-    private final float mMaxRange;
+    private final float mThreshold;
     private List<ProximitySensorListener> mListeners = new ArrayList<>();
     private String mTag = null;
     @VisibleForTesting ProximityEvent mLastEvent;
@@ -68,20 +67,27 @@
     public ProximitySensor(@Main Resources resources,
             AsyncSensorManager sensorManager) {
         mSensorManager = sensorManager;
-        Sensor sensor = findBrightnessSensor(resources);
 
+        Sensor sensor = findCustomProxSensor(resources);
+        float threshold = 0;
+        if (sensor != null) {
+            try {
+                threshold = getCustomProxThreshold(resources);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Can not load custom proximity sensor.", e);
+                sensor = null;
+            }
+        }
         if (sensor == null) {
-            mUsingBrightnessSensor = false;
             sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
-        } else {
-            mUsingBrightnessSensor = true;
+            if (sensor != null) {
+                threshold = sensor.getMaximumRange();
+            }
         }
+
+        mThreshold = threshold;
+
         mSensor = sensor;
-        if (mSensor != null) {
-            mMaxRange = mSensor.getMaximumRange();
-        } else {
-            mMaxRange = 0;
-        }
     }
 
     public void setTag(String tag) {
@@ -107,9 +113,15 @@
         mPaused = false;
         registerInternal();
     }
+    /**
+     * Returns a brightness sensor that can be used for proximity purposes.
+     */
+    private Sensor findCustomProxSensor(Resources resources) {
+        String sensorType = resources.getString(R.string.proximity_sensor_type);
+        if (sensorType.isEmpty()) {
+            return null;
+        }
 
-    private Sensor findBrightnessSensor(Resources resources) {
-        String sensorType = resources.getString(R.string.doze_brightness_sensor_type);
         List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
         Sensor sensor = null;
         for (Sensor s : sensorList) {
@@ -123,6 +135,17 @@
     }
 
     /**
+     * Returns a threshold value that can be used along with {@link #findCustomProxSensor}
+     */
+    private float getCustomProxThreshold(Resources resources) {
+        try {
+            return resources.getFloat(R.dimen.proximity_sensor_threshold);
+        } catch (Resources.NotFoundException e) {
+            throw new IllegalStateException("R.dimen.proximity_sensor_threshold must be set.");
+        }
+    }
+
+    /**
      * Returns true if we are registered with the SensorManager.
      */
     public boolean isRegistered() {
@@ -157,7 +180,6 @@
         if (mRegistered || mPaused || mListeners.isEmpty()) {
             return;
         }
-        logDebug("Using brightness sensor? " + mUsingBrightnessSensor);
         logDebug("Registering sensor listener");
         mRegistered = true;
         mSensorManager.registerListener(mSensorEventListener, mSensor, mSensorDelay);
@@ -196,10 +218,7 @@
     }
 
     private void onSensorEvent(SensorEvent event) {
-        boolean near = event.values[0] < mMaxRange;
-        if (mUsingBrightnessSensor) {
-            near = event.values[0] == 0;
-        }
+        boolean near = event.values[0] < mThreshold;
         mLastEvent = new ProximityEvent(near, event.timestamp);
         alertListeners();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java b/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java
new file mode 100644
index 0000000..d7c4e93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.util.time;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.text.format.DateFormat;
+
+import javax.inject.Inject;
+
+/**
+ * Instantiable wrapper around {@link DateFormat}.
+ */
+public class DateFormatUtil {
+    private final Context mContext;
+
+    @Inject
+    public DateFormatUtil(Context context) {
+        mContext = context;
+    }
+
+    /** Returns true if the phone is in 24 hour format. */
+    public boolean is24HourFormat() {
+        return DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
index 689eed9..678cfd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
@@ -34,6 +34,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Handler;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -72,6 +73,8 @@
     private Bitmap mWallpaperBitmap;
     @Mock
     private DozeParameters mDozeParam;
+    @Mock
+    private Handler mHandler;
 
     private CountDownLatch mEventCountdown;
 
@@ -104,7 +107,7 @@
         return new ImageWallpaper(mDozeParam) {
             @Override
             public Engine onCreateEngine() {
-                return new GLEngine(mMockContext, mDozeParam) {
+                return new GLEngine(mDozeParam, mHandler) {
                     @Override
                     public Context getDisplayContext() {
                         return mMockContext;
@@ -196,5 +199,6 @@
         when(mSurfaceHolder.getSurfaceFrame()).thenReturn(frame);
 
         assertThat(engineSpy.checkIfShouldStopTransition()).isEqualTo(assertion);
+        // destroy
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7ac5443..a36f2c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -86,7 +86,9 @@
     public void SysuiTeardown() {
         InstrumentationRegistry.registerInstance(mRealInstrumentation,
                 InstrumentationRegistry.getArguments());
-        // Reset the assert's testable looper to null.
+        if (TestableLooper.get(this) != null) {
+            TestableLooper.get(this).processAllMessages();
+        }
         disallowTestableLooperAsMainThread();
         SystemUIFactory.cleanup();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
index 545d2d4..5b78067 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
@@ -33,7 +33,9 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerFake;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -63,6 +65,7 @@
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
     private DockManager mDockManager = new DockManagerFake();
+    private StatusBarStateController mStatusBarStateController = new StatusBarStateControllerImpl();
 
     @Before
     public void setup() {
@@ -83,7 +86,7 @@
     public void test_brightLineFalsingManagerDisabled() {
         mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
                 mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor,
-                mDumpManager, mUiBgExecutor);
+                mDumpManager, mUiBgExecutor, mStatusBarStateController);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
     }
 
@@ -94,7 +97,7 @@
         mExecutor.runAllReady();
         mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
                 mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor,
-                mDumpManager, mUiBgExecutor);
+                mDumpManager, mUiBgExecutor, mStatusBarStateController);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class));
     }
 
@@ -102,7 +105,7 @@
     public void test_brightLineFalsingManagerToggled() throws InterruptedException {
         mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
                 mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor,
-                mDumpManager, mUiBgExecutor);
+                mDumpManager, mUiBgExecutor, mStatusBarStateController);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
 
         mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
index 0aaa3b6..8b5cc9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java
@@ -22,12 +22,16 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 import android.util.DisplayMetrics;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.util.sensors.ProximitySensor;
@@ -40,6 +44,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
 public class BrightLineFalsingManagerTest extends SysuiTestCase {
 
 
@@ -47,6 +52,7 @@
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
     private ProximitySensor mProximitySensor;
+    private SysuiStatusBarStateController mStatusBarStateController;
 
     private BrightLineFalsingManager mFalsingManager;
 
@@ -61,8 +67,11 @@
         FalsingDataProvider falsingDataProvider = new FalsingDataProvider(dm);
         DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake();
         DockManager dockManager = new DockManagerFake();
+        mStatusBarStateController = new StatusBarStateControllerImpl();
+        mStatusBarStateController.setState(StatusBarState.KEYGUARD);
         mFalsingManager = new BrightLineFalsingManager(falsingDataProvider,
-                mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager);
+                mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager,
+                mStatusBarStateController);
     }
 
     @Test
@@ -98,4 +107,12 @@
         mFalsingManager.onBouncerHidden();
         verify(mProximitySensor).register(any(ProximitySensor.ProximitySensorListener.class));
     }
+
+    @Test
+    public void testUnregisterSensor_StateTransition() {
+        mFalsingManager.onScreenTurningOn();
+        reset(mProximitySensor);
+        mStatusBarStateController.setState(StatusBarState.SHADE);
+        verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
new file mode 100644
index 0000000..68e1ec1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.PendingIntent
+import android.service.controls.Control
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlStatus
+import com.android.systemui.controls.controller.ControlInfo
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AllModelTest : SysuiTestCase() {
+
+    companion object {
+        private const val EMPTY_STRING = "Other"
+    }
+
+    @Mock
+    lateinit var pendingIntent: PendingIntent
+
+    val idPrefix = "controlId"
+    val favoritesIndices = listOf(7, 3, 1, 9)
+    val favoritesList = favoritesIndices.map { "controlId$it" }
+    lateinit var controls: List<ControlStatus>
+
+    lateinit var model: AllModel
+
+    private fun zoneMap(id: Int): String? {
+        return when (id) {
+            10 -> ""
+            11 -> null
+            else -> ((id + 1) % 3).toString()
+        }
+    }
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        // controlId0 --> zone = 1
+        // controlId1 --> zone = 2, favorite
+        // controlId2 --> zone = 0
+        // controlId3 --> zone = 1, favorite
+        // controlId4 --> zone = 2
+        // controlId5 --> zone = 0
+        // controlId6 --> zone = 1
+        // controlId7 --> zone = 2, favorite
+        // controlId8 --> zone = 0
+        // controlId9 --> zone = 1, favorite
+        // controlId10 --> zone = ""
+        // controlId11 --> zone = null
+        controls = (0..11).map {
+            ControlStatus(
+                    Control.StatelessBuilder("$idPrefix$it", pendingIntent)
+                            .setZone(zoneMap(it))
+                            .build(),
+                    it in favoritesIndices
+            )
+        }
+        model = AllModel(controls, favoritesList, EMPTY_STRING)
+    }
+
+    @Test
+    fun testElements() {
+
+        // Zones are sorted by order of appearance, with empty at the end with special header.
+        val expected = listOf(
+                ZoneNameWrapper("1"),
+                ControlWrapper(controls[0]),
+                ControlWrapper(controls[3]),
+                ControlWrapper(controls[6]),
+                ControlWrapper(controls[9]),
+                ZoneNameWrapper("2"),
+                ControlWrapper(controls[1]),
+                ControlWrapper(controls[4]),
+                ControlWrapper(controls[7]),
+                ZoneNameWrapper("0"),
+                ControlWrapper(controls[2]),
+                ControlWrapper(controls[5]),
+                ControlWrapper(controls[8]),
+                ZoneNameWrapper(EMPTY_STRING),
+                ControlWrapper(controls[10]),
+                ControlWrapper(controls[11])
+        )
+        expected.zip(model.elements).forEachIndexed { index, it ->
+            assertEquals("Error in item at index $index", it.first, it.second)
+        }
+    }
+
+    private fun sameControl(controlInfo: ControlInfo.Builder, control: Control): Boolean {
+        return controlInfo.controlId == control.controlId &&
+                controlInfo.controlTitle == control.title &&
+                controlInfo.deviceType == control.deviceType
+    }
+
+    @Test
+    fun testAllEmpty_noHeader() {
+        val selected_controls = listOf(controls[10], controls[11])
+        val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING)
+        val expected = listOf(
+                ControlWrapper(controls[10]),
+                ControlWrapper(controls[11])
+        )
+
+        expected.zip(new_model.elements).forEachIndexed { index, it ->
+            assertEquals("Error in item at index $index", it.first, it.second)
+        }
+    }
+
+    @Test
+    fun testFavorites() {
+        val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
+        model.favorites.zip(expectedFavorites).forEach {
+            assertTrue(sameControl(it.first, it.second))
+        }
+    }
+
+    @Test
+    fun testAddFavorite() {
+        val indexToAdd = 6
+        model.changeFavoriteStatus("$idPrefix$indexToAdd", true)
+
+        val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) +
+                controls[indexToAdd].control
+
+        model.favorites.zip(expectedFavorites).forEach {
+            assertTrue(sameControl(it.first, it.second))
+        }
+    }
+
+    @Test
+    fun testAddFavorite_alreadyThere() {
+        val indexToAdd = 7
+        model.changeFavoriteStatus("$idPrefix$indexToAdd", true)
+
+        val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
+
+        model.favorites.zip(expectedFavorites).forEach {
+            assertTrue(sameControl(it.first, it.second))
+        }
+    }
+
+    @Test
+    fun testRemoveFavorite() {
+        val indexToRemove = 3
+        model.changeFavoriteStatus("$idPrefix$indexToRemove", false)
+
+        val expectedFavorites = (favoritesIndices.filterNot { it == indexToRemove })
+                .map(controls::get)
+                .map(ControlStatus::control)
+
+        model.favorites.zip(expectedFavorites).forEach {
+            assertTrue(sameControl(it.first, it.second))
+        }
+    }
+
+    @Test
+    fun testRemoveFavorite_notThere() {
+        val indexToRemove = 4
+        model.changeFavoriteStatus("$idPrefix$indexToRemove", false)
+
+        val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control)
+
+        model.favorites.zip(expectedFavorites).forEach {
+            assertTrue(sameControl(it.first, it.second))
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index e917c93..c5b6969 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,8 +37,9 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -81,6 +82,7 @@
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
     @Mock private NotificationShadeWindowBlurController mNotificationShadeWindowBlurController;
+    @Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
 
     @Before
     public void setUp() {
@@ -116,7 +118,8 @@
                 mDockManager,
                 mNotificationShadeWindowBlurController,
                 mView,
-                mNotificationPanelViewController);
+                mNotificationPanelViewController,
+                mStatusBarViewFactory);
         mController.setupExpandedStatusBar();
         mController.setService(mStatusBar);
         mController.setDragDownHelper(mDragDownHelper);
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 d81b8c2..5253e2ca 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
@@ -247,6 +247,7 @@
     @Mock private KeyguardDismissUtil mKeyguardDismissUtil;
     @Mock private ExtensionController mExtensionController;
     @Mock private UserInfoControllerImpl mUserInfoControllerImpl;
+    @Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
     private ShadeController mShadeController;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
     private InitController mInitController = new InitController();
@@ -400,6 +401,7 @@
                 mKeyguardDismissUtil,
                 mExtensionController,
                 mUserInfoControllerImpl,
+                mPhoneStatusBarPolicy,
                 mDismissCallbackRegistry,
                 mStatusBarTouchableRegionManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index cd91f22..5771472 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -140,13 +139,16 @@
     }
 
     @Test
-    public void testDefault_hotspotNotSupported() {
-        assertFalse(mController.isHotspotSupported());
+    public void testHotspotSupported_default() {
+        assertTrue(mController.isHotspotSupported());
     }
 
     @Test
     public void testHotspotSupported_rightConditions() {
         mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
+
+        assertTrue(mController.isHotspotSupported());
+
         mTetheringCallbackCaptor.getValue()
                 .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);
 
@@ -154,13 +156,21 @@
     }
 
     @Test
-    public void testHotspotSupported_callbackCalledOnChange() {
+    public void testHotspotSupported_callbackCalledOnChange_tetheringSupported() {
         mController.addCallback(mCallback1);
-        mTetheringCallbackCaptor.getValue().onTetheringSupported(true);
+        mTetheringCallbackCaptor.getValue().onTetheringSupported(false);
+
+        verify(mCallback1).onHotspotAvailabilityChanged(false);
+    }
+
+    @Test
+    public void testHotspotSupported_callbackCalledOnChange_tetherableInterfaces() {
+        when(mTetheringInterfaceRegexps.getTetherableWifiRegexs())
+                .thenReturn(Collections.emptyList());
+        mController.addCallback(mCallback1);
         mTetheringCallbackCaptor.getValue()
                 .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps);
 
-        verify(mCallback1).onHotspotAvailabilityChanged(true);
+        verify(mCallback1).onHotspotAvailabilityChanged(false);
     }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 32da4c9..9c250c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -72,7 +72,7 @@
                     testSsid);
             setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true);
             verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
-                    null);
+                    testSsid);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 0c9130d0..e6b0440 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -86,6 +86,7 @@
         mContext.addMockService(comp, mKeyChainService);
 
         when(mUserManager.getUserInfo(anyInt())).thenReturn(new UserInfo());
+        when(mUserManager.isUserUnlocked(any())).thenReturn(true);
 
         when(mKeyChainService.getUserCaAliases())
                 .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
index 54cb0b8..31d884c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
@@ -20,11 +20,9 @@
 
 public class FakeProximitySensor extends ProximitySensor {
     private boolean mAvailable;
-    private boolean mPaused;
 
     public FakeProximitySensor(Resources resources, AsyncSensorManager sensorManager) {
         super(resources, sensorManager);
-
         mAvailable = true;
     }
 
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 3111ab7..0c37235 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -95,11 +95,7 @@
     // TODO (b/148190005): change to module-libs-api-stubs-current once it is ready.
     sdk_version: "core_platform",
     privileged: true,
-    // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies
-    // explicitly.
     jni_libs: [
-        "liblog",
-        "libnativehelper_compat_libc++",
         "libtetherutilsjni",
     ],
     resource_dirs: [
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index 789019c..2006fb3 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -32,7 +32,12 @@
      int32 system_ui_visibility = 8;
      bool is_translucent = 9;
      string top_activity_component = 10;
-     float scale = 11;
+     // deprecated because original width and height are stored now instead of the scale.
+     float legacy_scale = 11 [deprecated=true];
      int64 id = 12;
      int32 rotation = 13;
+     // The task width when the snapshot was taken
+     int32 task_width = 14;
+     // The task height when the snapshot was taken
+     int32 task_height = 15;
  }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a8a2791..ad21075 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -641,8 +641,8 @@
                     final SuspendDialogInfo dialogInfo =
                             mPackageManagerInternal.getSuspendedDialogInfo(providerPackage,
                                     suspendingPackage, providerUserId);
-                    // TODO(b/148035643): Send the original widget intent or ACTION_MAIN as an
-                    // IntentSender to SuspendedAppActivity.
+                    // onUnsuspend is null because we don't want to start any activity on
+                    // unsuspending from a suspended widget.
                     onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
                             providerPackage, suspendingPackage, dialogInfo, null, null,
                             providerUserId);
@@ -794,6 +794,8 @@
         proto.write(WidgetProto.PROVIDER_PACKAGE, widget.provider.id.componentName.getPackageName());
         proto.write(WidgetProto.PROVIDER_CLASS, widget.provider.id.componentName.getClassName());
         if (widget.options != null) {
+            proto.write(WidgetProto.RESTORE_COMPLETED,
+                    widget.options.getBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED));
             proto.write(WidgetProto.MIN_WIDTH,
                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 0));
             proto.write(WidgetProto.MIN_HEIGHT,
@@ -2509,7 +2511,8 @@
         out.endTag(null, "h");
     }
 
-    private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException {
+    private static void serializeAppWidget(XmlSerializer out, Widget widget,
+            boolean saveRestoreCompleted) throws IOException {
         out.startTag(null, "g");
         out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
         out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
@@ -2528,10 +2531,50 @@
             out.attribute(null, "max_height", Integer.toHexString((maxHeight > 0) ? maxHeight : 0));
             out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
                     AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
+            if (saveRestoreCompleted) {
+                boolean restoreCompleted = widget.options.getBoolean(
+                        AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED);
+                out.attribute(null, "restore_completed", Boolean.toString(restoreCompleted));
+            }
         }
         out.endTag(null, "g");
     }
 
+    private static Bundle parseWidgetIdOptions(XmlPullParser parser) {
+        Bundle options = new Bundle();
+        String restoreCompleted = parser.getAttributeValue(null, "restore_completed");
+        if (restoreCompleted != null) {
+            options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED,
+                    Boolean.valueOf(restoreCompleted));
+        }
+        String minWidthString = parser.getAttributeValue(null, "min_width");
+        if (minWidthString != null) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+                    Integer.parseInt(minWidthString, 16));
+        }
+        String minHeightString = parser.getAttributeValue(null, "min_height");
+        if (minHeightString != null) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+                    Integer.parseInt(minHeightString, 16));
+        }
+        String maxWidthString = parser.getAttributeValue(null, "max_width");
+        if (maxWidthString != null) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+                    Integer.parseInt(maxWidthString, 16));
+        }
+        String maxHeightString = parser.getAttributeValue(null, "max_height");
+        if (maxHeightString != null) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+                    Integer.parseInt(maxHeightString, 16));
+        }
+        String categoryString = parser.getAttributeValue(null, "host_category");
+        if (categoryString != null) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                    Integer.parseInt(categoryString, 16));
+        }
+        return options;
+    }
+
     @Override
     public List<String> getWidgetParticipants(int userId) {
         return mBackupRestoreController.getWidgetParticipants(userId);
@@ -3064,7 +3107,7 @@
                 if (widget.host.getUserId() != userId) {
                     continue;
                 }
-                serializeAppWidget(out, widget);
+                serializeAppWidget(out, widget, true);
             }
 
             Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator();
@@ -3203,34 +3246,7 @@
                         String restoredIdString = parser.getAttributeValue(null, "rid");
                         widget.restoredId = (restoredIdString == null) ? 0
                                 : Integer.parseInt(restoredIdString, 16);
-
-                        Bundle options = new Bundle();
-                        String minWidthString = parser.getAttributeValue(null, "min_width");
-                        if (minWidthString != null) {
-                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                                    Integer.parseInt(minWidthString, 16));
-                        }
-                        String minHeightString = parser.getAttributeValue(null, "min_height");
-                        if (minHeightString != null) {
-                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                                    Integer.parseInt(minHeightString, 16));
-                        }
-                        String maxWidthString = parser.getAttributeValue(null, "max_width");
-                        if (maxWidthString != null) {
-                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                                    Integer.parseInt(maxWidthString, 16));
-                        }
-                        String maxHeightString = parser.getAttributeValue(null, "max_height");
-                        if (maxHeightString != null) {
-                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                                    Integer.parseInt(maxHeightString, 16));
-                        }
-                        String categoryString = parser.getAttributeValue(null, "host_category");
-                        if (categoryString != null) {
-                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                                    Integer.parseInt(categoryString, 16));
-                        }
-                        widget.options = options;
+                        widget.options = parseWidgetIdOptions(parser);
 
                         final int hostTag = Integer.parseInt(parser.getAttributeValue(
                                 null, "h"), 16);
@@ -4382,7 +4398,7 @@
                         if (widget.host.isInPackageForUser(backedupPackage, userId)
                                 || (provider != null
                                 &&  provider.isInPackageForUser(backedupPackage, userId))) {
-                            serializeAppWidget(out, widget);
+                            serializeAppWidget(out, widget, false);
                         }
                     }
 
@@ -4815,36 +4831,6 @@
                     || widget.provider.getUserId() == userId);
         }
 
-        private Bundle parseWidgetIdOptions(XmlPullParser parser) {
-            Bundle options = new Bundle();
-            String minWidthString = parser.getAttributeValue(null, "min_width");
-            if (minWidthString != null) {
-                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                        Integer.parseInt(minWidthString, 16));
-            }
-            String minHeightString = parser.getAttributeValue(null, "min_height");
-            if (minHeightString != null) {
-                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                        Integer.parseInt(minHeightString, 16));
-            }
-            String maxWidthString = parser.getAttributeValue(null, "max_width");
-            if (maxWidthString != null) {
-                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                        Integer.parseInt(maxWidthString, 16));
-            }
-            String maxHeightString = parser.getAttributeValue(null, "max_height");
-            if (maxHeightString != null) {
-                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                        Integer.parseInt(maxHeightString, 16));
-            }
-            String categoryString = parser.getAttributeValue(null, "host_category");
-            if (categoryString != null) {
-                options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                        Integer.parseInt(categoryString, 16));
-            }
-            return options;
-        }
-
         private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) {
             int pending = 0;
             final int N = updates.size();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4da60b8..3180ceb 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,6 +99,7 @@
         "android.hardware.vibrator-java",
         "app-compat-annotations",
         "framework-tethering-stubs",
+        "ike-stubs",
     ],
 
     required: [
@@ -126,7 +127,6 @@
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
         "netd_event_listener_interface-java",
-        "ike-stubs",
     ],
 
     plugins: [
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 7ccb284..7aaf9be 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -144,6 +144,18 @@
         public File getAdbTempKeysFile() {
             return mDebuggingManager.getAdbTempKeysFile();
         }
+
+        @Override
+        public void startAdbdForTransport(byte transportType) {
+            FgThread.getHandler().sendMessage(obtainMessage(
+                    AdbService::setAdbdEnabledForTransport, AdbService.this, true, transportType));
+        }
+
+        @Override
+        public void stopAdbdForTransport(byte transportType) {
+            FgThread.getHandler().sendMessage(obtainMessage(
+                    AdbService::setAdbdEnabledForTransport, AdbService.this, false, transportType));
+        }
     }
 
     private void initAdbState() {
@@ -437,6 +449,19 @@
         }
     }
 
+    private void setAdbdEnabledForTransport(boolean enable, byte transportType) {
+        if (transportType == AdbTransportType.USB) {
+            mIsAdbUsbEnabled = enable;
+        } else if (transportType == AdbTransportType.WIFI) {
+            mIsAdbWifiEnabled = enable;
+        }
+        if (enable) {
+            startAdbd();
+        } else {
+            stopAdbd();
+        }
+    }
+
     private void setAdbEnabled(boolean enable, byte transportType) {
         if (DEBUG) {
             Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7f98c7f..f408fe7 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
@@ -36,6 +37,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -88,11 +90,13 @@
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.webkit.WebViewZygote;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -177,6 +181,10 @@
     /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */
     private ArrayList<ServiceRecord> mTmpCollectionResults = null;
 
+    /** Mapping from uid to their foreground service AppOpCallbacks (if they have one). */
+    @GuardedBy("mAm")
+    private final SparseArray<AppOpCallback> mFgsAppOpCallbacks = new SparseArray<>();
+
     /**
      * For keeping ActiveForegroundApps retaining state while the screen is off.
      */
@@ -685,8 +693,8 @@
 
         if (!r.mAllowWhileInUsePermissionInFgs) {
             r.mAllowWhileInUsePermissionInFgs =
-                    shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid,
-                            service, r, allowBackgroundActivityStarts);
+                    shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
+                            callingUid, service, r, allowBackgroundActivityStarts);
         }
 
         return cmp;
@@ -1455,7 +1463,9 @@
                                 null, true, false, "");
                         FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                                 r.appInfo.uid, r.shortInstanceName,
-                                FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
+                                FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
+                                r.mAllowWhileInUsePermissionInFgs);
+                        registerAppOpCallbackLocked(r);
                         mAm.updateForegroundServiceUsageStats(r.name, r.userId, true);
                     }
                     r.postNotification();
@@ -1504,9 +1514,11 @@
                 mAm.mAppOpsService.finishOperation(
                         AppOpsManager.getToken(mAm.mAppOpsService),
                         AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
+                unregisterAppOpCallbackLocked(r);
                 FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                         r.appInfo.uid, r.shortInstanceName,
-                        FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
+                        FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
+                        r.mAllowWhileInUsePermissionInFgs);
                 mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
                 if (r.app != null) {
                     mAm.updateLruProcessLocked(r.app, false, null);
@@ -1527,6 +1539,207 @@
         }
     }
 
+    /** Registers an AppOpCallback for monitoring special AppOps for this foreground service. */
+    private void registerAppOpCallbackLocked(@NonNull ServiceRecord r) {
+        if (r.app == null) {
+            return;
+        }
+        final int uid = r.appInfo.uid;
+        AppOpCallback callback = mFgsAppOpCallbacks.get(uid);
+        if (callback == null) {
+            callback = new AppOpCallback(r.app, mAm.getAppOpsManager());
+            mFgsAppOpCallbacks.put(uid, callback);
+        }
+        callback.registerLocked();
+    }
+
+    /** Unregisters a foreground service's AppOpCallback. */
+    private void unregisterAppOpCallbackLocked(@NonNull ServiceRecord r) {
+        final int uid = r.appInfo.uid;
+        final AppOpCallback callback = mFgsAppOpCallbacks.get(uid);
+        if (callback != null) {
+            callback.unregisterLocked();
+            if (callback.isObsoleteLocked()) {
+                mFgsAppOpCallbacks.remove(uid);
+            }
+        }
+    }
+
+    /**
+     * For monitoring when {@link #LOGGED_AP_OPS} AppOps occur by an app while it is holding
+     * at least one foreground service and is not also in the TOP state.
+     * Once the uid no longer holds any foreground services, this callback becomes stale
+     * (marked by {@link #isObsoleteLocked()}) and must no longer be used.
+     *
+     * Methods that end in Locked should only be called while the mAm lock is held.
+     */
+    private static final class AppOpCallback {
+        /** AppOps that should be logged if they occur during a foreground service. */
+        private static final int[] LOGGED_AP_OPS = new int[] {
+                AppOpsManager.OP_COARSE_LOCATION,
+                AppOpsManager.OP_FINE_LOCATION,
+                AppOpsManager.OP_RECORD_AUDIO,
+                AppOpsManager.OP_CAMERA
+        };
+
+        private final ProcessRecord mProcessRecord;
+
+        /** Count of acceptances per appop (for LOGGED_AP_OPS) during this fgs session. */
+        @GuardedBy("mCounterLock")
+        private final SparseIntArray mAcceptedOps = new SparseIntArray();
+        /** Count of rejections per appop (for LOGGED_AP_OPS) during this fgs session. */
+        @GuardedBy("mCounterLock")
+        private final SparseIntArray mRejectedOps = new SparseIntArray();
+
+        /** Lock for the purposes of mAcceptedOps and mRejectedOps. */
+        private final Object mCounterLock = new Object();
+
+        /**
+         * AppOp Mode (e.g. {@link AppOpsManager#MODE_ALLOWED} per op.
+         * This currently cannot change without the process being killed, so they are constants.
+         */
+        private final SparseIntArray mAppOpModes = new SparseIntArray();
+
+        /**
+         * Number of foreground services currently associated with this AppOpCallback (i.e.
+         * currently held for this uid).
+         */
+        @GuardedBy("mAm")
+        private int mNumFgs = 0;
+
+        /**
+         * Indicates that this Object is stale and must not be used.
+         * Specifically, when mNumFgs decreases down to 0, the callbacks will be unregistered and
+         * this AppOpCallback is unusable.
+         */
+        @GuardedBy("mAm")
+        private boolean mDestroyed = false;
+
+        private final AppOpsManager mAppOpsManager;
+
+        AppOpCallback(@NonNull ProcessRecord r, @NonNull AppOpsManager appOpsManager) {
+            mProcessRecord = r;
+            mAppOpsManager = appOpsManager;
+            for (int op : LOGGED_AP_OPS) {
+                int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, r.uid, r.info.packageName);
+                mAppOpModes.put(op, mode);
+            }
+        }
+
+        private final AppOpsManager.OnOpNotedListener mOpNotedCallback =
+                new AppOpsManager.OnOpNotedListener() {
+                    @Override
+                    public void onOpNoted(int op, int uid, String pkgName, int result) {
+                        if (uid == mProcessRecord.uid && isNotTop()) {
+                            incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED);
+                        }
+                    }
+        };
+
+        private final AppOpsManager.OnOpActiveChangedInternalListener mOpActiveCallback =
+                new AppOpsManager.OnOpActiveChangedInternalListener() {
+                    @Override
+                    public void onOpActiveChanged(int op, int uid, String pkgName, boolean active) {
+                        if (uid == mProcessRecord.uid && active && isNotTop()) {
+                            incrementOpCount(op, true);
+                        }
+                    }
+        };
+
+        private boolean isNotTop() {
+            return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP;
+        }
+
+        private void incrementOpCount(int op, boolean allowed) {
+            synchronized (mCounterLock) {
+                final SparseIntArray counter = allowed ? mAcceptedOps : mRejectedOps;
+                final int index = counter.indexOfKey(op);
+                if (index < 0) {
+                    counter.put(op, 1);
+                } else {
+                    counter.setValueAt(index, counter.valueAt(index) + 1);
+                }
+            }
+        }
+
+        void registerLocked() {
+            if (isObsoleteLocked()) {
+                Slog.wtf(TAG, "Trying to register on a stale AppOpCallback.");
+                return;
+            }
+            mNumFgs++;
+            if (mNumFgs == 1) {
+                mAppOpsManager.startWatchingNoted(LOGGED_AP_OPS, mOpNotedCallback);
+                mAppOpsManager.startWatchingActive(LOGGED_AP_OPS, mOpActiveCallback);
+            }
+        }
+
+        void unregisterLocked() {
+            mNumFgs--;
+            if (mNumFgs <= 0) {
+                mDestroyed = true;
+                logFinalValues();
+                mAppOpsManager.stopWatchingNoted(mOpNotedCallback);
+                mAppOpsManager.stopWatchingActive(mOpActiveCallback);
+            }
+        }
+
+        /**
+         * Indicates that all foreground services for this uid are now over and the callback is
+         * stale and must never be used again.
+         */
+        boolean isObsoleteLocked() {
+            return mDestroyed;
+        }
+
+        private void logFinalValues() {
+            synchronized (mCounterLock) {
+                for (int op : LOGGED_AP_OPS) {
+                    final int acceptances = mAcceptedOps.get(op);
+                    final int rejections = mRejectedOps.get(op);
+                    if (acceptances > 0 ||  rejections > 0) {
+                        FrameworkStatsLog.write(
+                                FrameworkStatsLog.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED,
+                                mProcessRecord.uid, opToEnum(op),
+                                modeToEnum(mAppOpModes.get(op)),
+                                acceptances, rejections
+                        );
+                    }
+                }
+            }
+        }
+
+        /** Maps AppOp mode to atoms.proto enum. */
+        private static int modeToEnum(int mode) {
+            switch (mode) {
+                case AppOpsManager.MODE_ALLOWED: return FrameworkStatsLog
+                        .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_ALLOWED;
+                case AppOpsManager.MODE_IGNORED: return FrameworkStatsLog
+                        .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_IGNORED;
+                case AppOpsManager.MODE_FOREGROUND: return FrameworkStatsLog
+                        .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_FOREGROUND;
+                default: return FrameworkStatsLog
+                        .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_UNKNOWN;
+            }
+        }
+    }
+
+    /** Maps AppOp op value to atoms.proto enum. */
+    private static int opToEnum(int op) {
+        switch (op) {
+            case AppOpsManager.OP_COARSE_LOCATION: return FrameworkStatsLog
+                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_COARSE_LOCATION;
+            case AppOpsManager.OP_FINE_LOCATION: return FrameworkStatsLog
+                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_FINE_LOCATION;
+            case AppOpsManager.OP_CAMERA: return FrameworkStatsLog
+                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_CAMERA;
+            case AppOpsManager.OP_RECORD_AUDIO: return FrameworkStatsLog
+                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_RECORD_AUDIO;
+            default: return FrameworkStatsLog
+                    .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_NONE;
+        }
+    }
+
     private void cancelForegroundNotificationLocked(ServiceRecord r) {
         if (r.foregroundId != 0) {
             // First check to see if this app has any other active foreground services
@@ -1865,9 +2078,9 @@
             }
 
             if (!s.mAllowWhileInUsePermissionInFgs) {
-                final int callingUid = Binder.getCallingUid();
                 s.mAllowWhileInUsePermissionInFgs =
-                        shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid,
+                        shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
+                                Binder.getCallingPid(), Binder.getCallingUid(),
                                 service, s, false);
             }
 
@@ -3136,9 +3349,11 @@
             mAm.mAppOpsService.finishOperation(
                     AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
+            unregisterAppOpCallbackLocked(r);
             FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                     r.appInfo.uid, r.shortInstanceName,
-                    FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
+                    FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
+                    r.mAllowWhileInUsePermissionInFgs);
             mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
         }
 
@@ -4625,7 +4840,8 @@
      * @return true if allow, false otherwise.
      */
     private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
-            int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
+            int callingPid, int callingUid, Intent intent, ServiceRecord r,
+            boolean allowBackgroundActivityStarts) {
         // Is the background FGS start restriction turned on?
         if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
             return true;
@@ -4635,13 +4851,6 @@
             return true;
         }
 
-        // Is the service in a whitelist?
-        final boolean hasAllowBackgroundActivityStartsToken = r.app != null
-                ? r.app.mAllowBackgroundActivityStartsTokens.contains(r) : false;
-        if (hasAllowBackgroundActivityStartsToken) {
-            return true;
-        }
-
         boolean isCallerSystem = false;
         final int callingAppId = UserHandle.getAppId(callingUid);
         switch (callingAppId) {
@@ -4660,6 +4869,24 @@
             return true;
         }
 
+        if (r.app != null) {
+            ActiveInstrumentation instr = r.app.getActiveInstrumentation();
+            if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
+                return true;
+            }
+        }
+
+        final boolean hasAllowBackgroundActivityStartsToken = r.app != null
+                ? !r.app.mAllowBackgroundActivityStartsTokens.isEmpty() : false;
+        if (hasAllowBackgroundActivityStartsToken) {
+            return true;
+        }
+
+        if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
+                == PERMISSION_GRANTED) {
+            return true;
+        }
+
         // Is the calling UID at PROCESS_STATE_TOP or above?
         final boolean isCallingUidTopApp = appIsTopLocked(callingUid);
         if (isCallingUidTopApp) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cea3bb8..b2fb530 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6515,14 +6515,6 @@
     }
 
     @Override
-    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
-            Rect tempDockedTaskInsetBounds,
-            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
-        mActivityTaskManager.resizeDockedStack(dockedBounds, tempDockedTaskBounds,
-                tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds);
-    }
-
-    @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
         mActivityTaskManager.positionTaskInStack(taskId, stackId, position);
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index bf79729..2941e77 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2570,8 +2570,6 @@
         switch (op) {
             case "move-task":
                 return runStackMoveTask(pw);
-            case "resize-docked-stack":
-                return runStackResizeDocked(pw);
             case "positiontask":
                 return runStackPositionTask(pw);
             case "list":
@@ -2646,17 +2644,6 @@
         return 0;
     }
 
-    int runStackResizeDocked(PrintWriter pw) throws RemoteException {
-        final Rect bounds = getBounds();
-        final Rect taskBounds = getBounds();
-        if (bounds == null || taskBounds == null) {
-            getErrPrintWriter().println("Error: invalid input bounds");
-            return -1;
-        }
-        mTaskInterface.resizeDockedStack(bounds, taskBounds, null, null, null);
-        return 0;
-    }
-
     int runStackPositionTask(PrintWriter pw) throws RemoteException {
         String taskIdStr = getNextArgRequired();
         int taskId = Integer.parseInt(taskIdStr);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 7cb8458..612fd39 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -178,6 +178,8 @@
             float maxRefreshRate = Float.POSITIVE_INFINITY;
             int lowestConsideredPriority = Vote.MIN_PRIORITY;
             while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+                minRefreshRate = 0f;
+                maxRefreshRate = Float.POSITIVE_INFINITY;
                 int height = Vote.INVALID_SIZE;
                 int width = Vote.INVALID_SIZE;
 
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 63054cf..fd8e159 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -40,7 +40,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.Signature;
@@ -202,7 +201,7 @@
                                 intent,
                                 /* onFinished= */ null,
                                 /* handler= */ null);
-                    } catch (IntentSender.SendIntentException e) {
+                    } catch (Exception e) {
                         Slog.e(TAG, "Error sending status feedback.", e);
                     }
                 });
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c9c6d51..ceb1cd4 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -51,6 +51,7 @@
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_FOREGROUND_SERVICE;
 import static android.content.Context.BIND_NOT_PERCEPTIBLE;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
@@ -3448,16 +3449,10 @@
             ArrayList<ConversationChannelWrapper> conversations =
                     mPreferencesHelper.getConversations(onlyImportant);
             for (ConversationChannelWrapper conversation : conversations) {
-                LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
-                        .setPackage(conversation.getPkg())
-                        .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
-                        .setShortcutIds(Arrays.asList(
-                                conversation.getNotificationChannel().getConversationId()));
-                List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(
-                        query, UserHandle.of(UserHandle.getUserId(conversation.getUid())));
-                if (shortcuts != null && !shortcuts.isEmpty()) {
-                    conversation.setShortcutInfo(shortcuts.get(0));
-                }
+                conversation.setShortcutInfo(getShortcutInfo(
+                        conversation.getNotificationChannel().getConversationId(),
+                        conversation.getPkg(),
+                        UserHandle.of(UserHandle.getUserId(conversation.getUid()))));
             }
             return new ParceledListSlice<>(conversations);
         }
@@ -3477,16 +3472,10 @@
             ArrayList<ConversationChannelWrapper> conversations =
                     mPreferencesHelper.getConversations(pkg, uid);
             for (ConversationChannelWrapper conversation : conversations) {
-                LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
-                        .setPackage(pkg)
-                        .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
-                        .setShortcutIds(Arrays.asList(
-                                conversation.getNotificationChannel().getConversationId()));
-                List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(
-                        query, UserHandle.of(UserHandle.getUserId(uid)));
-                if (shortcuts != null && !shortcuts.isEmpty()) {
-                    conversation.setShortcutInfo(shortcuts.get(0));
-                }
+                conversation.setShortcutInfo(getShortcutInfo(
+                        conversation.getNotificationChannel().getConversationId(),
+                        pkg,
+                        UserHandle.of(UserHandle.getUserId(uid))));
             }
             return new ParceledListSlice<>(conversations);
         }
@@ -5646,6 +5635,8 @@
             }
         }
 
+        r.setShortcutInfo(getShortcutInfo(notification.getShortcutId(), pkg, user));
+
         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                 r.getSbn().getOverrideGroupKey() != null)) {
             return;
@@ -5959,20 +5950,33 @@
         return false;
     }
 
+    private ShortcutInfo getShortcutInfo(String shortcutId, String packageName, UserHandle user) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (shortcutId == null || packageName == null || user == null) {
+                return null;
+            }
+            LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+            if (packageName != null) {
+                query.setPackage(packageName);
+            }
+            if (shortcutId != null) {
+                query.setShortcutIds(Arrays.asList(shortcutId));
+            }
+            query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED);
+            List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user);
+            ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0
+                    ? shortcuts.get(0)
+                    : null;
+            return shortcutInfo;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) {
-        LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
-        if (packageName != null) {
-            query.setPackage(packageName);
-        }
-        if (shortcutId != null) {
-            query.setShortcutIds(Arrays.asList(shortcutId));
-        }
-        query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED);
-        List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user);
-        ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0
-                ? shortcuts.get(0)
-                : null;
-        return shortcutInfo != null;
+        ShortcutInfo shortcutInfo = getShortcutInfo(shortcutId, packageName, user);
+        return shortcutInfo != null && shortcutInfo.isLongLived();
     }
 
     private void logBubbleError(String key, String failureMessage) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f92e1fc..9d243e4 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -35,6 +35,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Bitmap;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
@@ -166,6 +167,7 @@
     private boolean mAllowBubble;
     private Light mLight;
     private boolean mIsNotConversationOverride;
+    private ShortcutInfo mShortcutInfo;
     /**
      * This list contains system generated smart actions from NAS, app-generated smart actions are
      * stored in Notification.actions with isContextual() set to true.
@@ -1338,14 +1340,20 @@
         return hasCustomRemoteView && !hasDecoratedStyle;
     }
 
-    /** Whether this notification is a conversation notification. */
+    public void setShortcutInfo(ShortcutInfo shortcutInfo) {
+        mShortcutInfo = shortcutInfo;
+    }
+
+    /**
+     * Whether this notification is a conversation notification.
+     */
     public boolean isConversation() {
         Notification notification = getNotification();
         if (mChannel.isDemoted()
                 || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
             return false;
         }
-        if (notification.getShortcutId() == null
+        if (mShortcutInfo == null
                 && !FeatureFlagUtils.isEnabled(
                         mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) {
             return false;
@@ -1353,7 +1361,6 @@
         if (mIsNotConversationOverride) {
             return false;
         }
-        // STOPSHIP b/137397357: Check shortcut to make a further decision
         return true;
     }
 
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index e86a42c..f497f11 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -57,6 +57,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.IntentResolver;
 import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.PackageInfoUtils.CachedApplicationInfoGenerator;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
@@ -273,9 +274,7 @@
             return null;
         }
         List<ProviderInfo> providerList = null;
-
-        // Map from a package name to the corresponding app info.
-        ArrayMap<String, ApplicationInfo> appInfos = null;
+        CachedApplicationInfoGenerator appInfoGenerator = null;
         synchronized (mLock) {
             for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) {
                 final ParsedProvider p = mProviders.mProviders.valueAt(i);
@@ -304,26 +303,15 @@
                         && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) {
                     continue;
                 }
-
-                // Make sure we have AppInfo for this provider.
-                final PackageUserState state = ps.readUserState(userId);
-                ApplicationInfo appInfo =
-                        (appInfos == null) ? null : appInfos.get(pkg.getPackageName());
-                if (appInfo == null) {
-                    appInfo = PackageInfoUtils.generateApplicationInfo(
-                            pkg, flags, state, userId, ps);
-                    if (appInfo == null) {
-                        // In this case, we should avoid calling generateApplicationInfo() for
-                        // the same package in subsequent iterations, but appInfo shouldn't be null
-                        // here, so we don't bother.
-                        continue;
-                    }
-                    if (appInfos == null) {
-                        appInfos = new ArrayMap<>(4);
-                    }
-                    appInfos.put(pkg.getPackageName(), appInfo);
+                if (appInfoGenerator == null) {
+                    appInfoGenerator = new CachedApplicationInfoGenerator();
                 }
-                // At this point, appInfo != null.
+                final PackageUserState state = ps.readUserState(userId);
+                final ApplicationInfo appInfo =
+                        appInfoGenerator.generate(pkg, flags, state, userId, ps);
+                if (appInfo == null) {
+                    continue;
+                }
 
                 final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
                         pkg, p, flags, state, appInfo, userId, ps);
@@ -355,14 +343,20 @@
             if (pkg == null) {
                 return null;
             }
-            return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
-                    ps.readUserState(userId), userId, ps);
+            final PackageUserState state = ps.readUserState(userId);
+            ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
+                    pkg, flags, state, userId, ps);
+            if (appInfo == null) {
+                return null;
+            }
+            return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, appInfo, userId, ps);
         }
     }
 
     void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo, boolean safeMode,
             int userId) {
         synchronized (mLock) {
+            CachedApplicationInfoGenerator appInfoGenerator = null;
             for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) {
                 final ParsedProvider p = mProvidersByAuthority.valueAt(i);
                 if (!p.isSyncable()) {
@@ -384,9 +378,18 @@
                 if (safeMode && !pkg.isSystem()) {
                     continue;
                 }
-                final ProviderInfo info =
-                        PackageInfoUtils.generateProviderInfo(pkg, p, 0,
-                                ps.readUserState(userId), userId, ps);
+                if (appInfoGenerator == null) {
+                    appInfoGenerator = new CachedApplicationInfoGenerator();
+                }
+                final PackageUserState state = ps.readUserState(userId);
+                final ApplicationInfo appInfo =
+                        appInfoGenerator.generate(pkg, 0, state, userId, ps);
+                if (appInfo == null) {
+                    continue;
+                }
+
+                final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
+                        pkg, p, 0, state, appInfo, userId, ps);
                 if (info == null) {
                     continue;
                 }
@@ -1731,8 +1734,13 @@
             if (userState.instantApp && ps.isUpdateAvailable()) {
                 return null;
             }
+            final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
+                    pkg, mFlags, userState, userId, ps);
+            if (appInfo == null) {
+                return null;
+            }
             ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, mFlags,
-                    userState, userId, ps);
+                    userState, appInfo, userId, ps);
             if (pi == null) {
                 return null;
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4eac79c..f714af03 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5459,7 +5459,13 @@
                     return null;
                 }
                 PackageUserState state = ps.readUserState(userId);
-                return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId, ps);
+                final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
+                        pkg, flags, state, userId, ps);
+                if (appInfo == null) {
+                    return null;
+                }
+                return PackageInfoUtils.generateProviderInfo(
+                        pkg, p, flags, state, appInfo, userId, ps);
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index f5ce080..4ab1f39 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -48,7 +48,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
+import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.PackageSetting;
@@ -61,6 +61,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 
@@ -72,6 +73,7 @@
  * @hide
  **/
 public class PackageInfoUtils {
+    private static final String TAG = PackageParser2.TAG;
 
     /**
      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
@@ -312,35 +314,22 @@
 
     /**
      * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
-     *
-     * @deprecated use {@link #generateProviderInfo(
-     * AndroidPackage, ParsedProvider, int, PackageUserState, ApplicationInfo, int, PackageSetting)}
-     * instead and pass {@link ApplicationInfo} explicitly to avoid generating duplicate instances
-     * of it.
-     */
-    @Nullable
-    @Deprecated
-    public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
-            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId,
-            @Nullable PackageSetting pkgSetting) {
-        return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
-    }
-
-    /**
-     * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
      */
     @Nullable
     public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
             @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
-            @Nullable ApplicationInfo applicationInfo, int userId,
+            @NonNull ApplicationInfo applicationInfo, int userId,
             @Nullable PackageSetting pkgSetting) {
         if (p == null) return null;
+        if (applicationInfo == null || !pkg.getPackageName().equals(applicationInfo.packageName)) {
+            Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName()
+                    + " actual=" + (applicationInfo == null ? "(null AppInfo)"
+                    : applicationInfo.packageName));
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
+        }
         if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
             return null;
         }
-        if (applicationInfo == null) {
-            applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
-        }
         ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
                 applicationInfo, userId);
         if (info == null) {
@@ -486,4 +475,29 @@
                 | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
         // @formatter:on
     }
+
+    /**
+     * Wraps {@link PackageInfoUtils#generateApplicationInfo} with a cache.
+     */
+    public static class CachedApplicationInfoGenerator {
+        // Map from a package name to the corresponding app info.
+        private ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>();
+
+        /**
+         * {@link PackageInfoUtils#generateApplicationInfo} with a cache.
+         */
+        @Nullable
+        public ApplicationInfo generate(AndroidPackage pkg,
+                @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId,
+                @Nullable PackageSetting pkgSetting) {
+            ApplicationInfo appInfo = mCache.get(pkg.getPackageName());
+            if (appInfo != null) {
+                return appInfo;
+            }
+            appInfo = PackageInfoUtils.generateApplicationInfo(
+                    pkg, flags, state, userId, pkgSetting);
+            mCache.put(pkg.getPackageName(), appInfo);
+            return appInfo;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index f99791a..d561b9c 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -42,7 +42,7 @@
  */
 public class PackageParser2 {
 
-    private static final String TAG = "PackageParser2";
+    static final String TAG = "PackageParser2";
 
     private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
     private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b40c2c1..1b5cc6a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3090,7 +3090,7 @@
                         event.getAction(), fallbackAction.keyCode,
                         event.getRepeatCount(), fallbackAction.metaState,
                         event.getDeviceId(), event.getScanCode(),
-                        flags, event.getSource(), event.getDisplayId(), null /* hmac */, null);
+                        flags, event.getSource(), event.getDisplayId(), null);
 
                 if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) {
                     fallbackEvent.recycle();
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index 233417d..059861b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -16,8 +16,13 @@
 package com.android.server.power.batterysaver;
 
 import android.annotation.IntDef;
+import android.app.UiModeManager;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.BatterySaverPolicyConfig;
@@ -183,18 +188,15 @@
     private String mEventLogKeys;
 
     /**
-     * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
-     * is true *and* {@link #mAccessibilityEnabled} is false.
-     */
-    @GuardedBy("mLock")
-    private boolean mDisableVibrationEffective;
-
-    /**
      * Whether accessibility is currently enabled or not.
      */
     @GuardedBy("mLock")
     private boolean mAccessibilityEnabled;
 
+    /** Whether the phone is projecting in car mode or not. */
+    @GuardedBy("mLock")
+    private boolean mCarModeEnabled;
+
     /** The current default adaptive policy. */
     @GuardedBy("mLock")
     private Policy mDefaultAdaptivePolicy = DEFAULT_ADAPTIVE_POLICY;
@@ -207,6 +209,13 @@
     @GuardedBy("mLock")
     private Policy mFullPolicy = DEFAULT_FULL_POLICY;
 
+    /**
+     * The current effective policy. This is based on the current policy level's policy, with any
+     * required adjustments.
+     */
+    @GuardedBy("mLock")
+    private Policy mEffectivePolicy = OFF_POLICY;
+
     @IntDef(prefix = {"POLICY_LEVEL_"}, value = {
             POLICY_LEVEL_OFF,
             POLICY_LEVEL_ADAPTIVE,
@@ -230,6 +239,20 @@
     private final ContentResolver mContentResolver;
     private final BatterySavingStats mBatterySavingStats;
 
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED:
+                    setCarModeEnabled(true);
+                    break;
+                case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED:
+                    setCarModeEnabled(false);
+                    break;
+            }
+        }
+    };
+
     @GuardedBy("mLock")
     private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
 
@@ -263,16 +286,25 @@
 
         final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
 
-        acm.addAccessibilityStateChangeListener((enabled) -> {
-            synchronized (mLock) {
-                mAccessibilityEnabled = enabled;
-            }
-            refreshSettings();
-        });
-        final boolean enabled = acm.isEnabled();
+        acm.addAccessibilityStateChangeListener((enabled) -> setAccessibilityEnabled(enabled));
+        final boolean accessibilityEnabled = acm.isEnabled();
         synchronized (mLock) {
-            mAccessibilityEnabled = enabled;
+            mAccessibilityEnabled = accessibilityEnabled;
         }
+
+        final IntentFilter filter = new IntentFilter(
+                UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
+        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+        // The ENTER/EXIT_CAR_MODE_PRIORITIZED intents are sent to UserHandle.ALL, so no need to
+        // register as all users here.
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+        final boolean carModeEnabled =
+                mContext.getSystemService(UiModeManager.class).getCurrentModeType()
+                        == Configuration.UI_MODE_TYPE_CAR;
+        synchronized (mLock) {
+            mCarModeEnabled = carModeEnabled;
+        }
+
         onChange(true, null);
     }
 
@@ -299,13 +331,34 @@
         PowerManager.invalidatePowerSaveModeCaches();
     }
 
+    /**
+     * Notifies listeners of a policy change on the handler thread only if the current policy level
+     * is not {@link POLICY_LEVEL_OFF}.
+     */
+    private void maybeNotifyListenersOfPolicyChange() {
+        final BatterySaverPolicyListener[] listeners;
+        synchronized (mLock) {
+            if (getPolicyLevelLocked() == POLICY_LEVEL_OFF) {
+                // Current policy is OFF, so there's no change to notify listeners of.
+                return;
+            }
+            // Don't call out to listeners with the lock held.
+            listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
+        }
+
+        mHandler.post(() -> {
+            for (BatterySaverPolicyListener listener : listeners) {
+                listener.onBatterySaverPolicyChanged(this);
+            }
+        });
+    }
+
     @Override
     public void onChange(boolean selfChange, Uri uri) {
         refreshSettings();
     }
 
     private void refreshSettings() {
-        final BatterySaverPolicyListener[] listeners;
         synchronized (mLock) {
             // Load the non-device-specific setting.
             final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
@@ -334,16 +387,9 @@
                 // Nothing of note changed.
                 return;
             }
-
-            listeners = mListeners.toArray(new BatterySaverPolicyListener[0]);
         }
 
-        // Notify the listeners.
-        mHandler.post(() -> {
-            for (BatterySaverPolicyListener listener : listeners) {
-                listener.onBatterySaverPolicyChanged(this);
-            }
-        });
+        maybeNotifyListenersOfPolicyChange();
     }
 
     @GuardedBy("mLock")
@@ -404,31 +450,63 @@
 
     @GuardedBy("mLock")
     private void updatePolicyDependenciesLocked() {
-        final Policy currPolicy = getCurrentPolicyLocked();
-        // Update the effective vibration policy.
-        mDisableVibrationEffective = currPolicy.disableVibration
-                && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
+        final Policy rawPolicy = getCurrentRawPolicyLocked();
+
+        final int locationMode;
+        if (mCarModeEnabled
+                && rawPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE
+                && rawPolicy.locationMode != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) {
+            // If car projection is enabled, ensure that navigation works.
+            locationMode = PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
+        } else {
+            locationMode = rawPolicy.locationMode;
+        }
+        mEffectivePolicy = new Policy(
+                rawPolicy.adjustBrightnessFactor,
+                rawPolicy.advertiseIsEnabled,
+                rawPolicy.deferFullBackup,
+                rawPolicy.deferKeyValueBackup,
+                rawPolicy.disableAnimation,
+                rawPolicy.disableAod,
+                rawPolicy.disableLaunchBoost,
+                rawPolicy.disableOptionalSensors,
+                rawPolicy.disableSoundTrigger,
+                // Don't disable vibration when accessibility is on.
+                rawPolicy.disableVibration && !mAccessibilityEnabled,
+                rawPolicy.enableAdjustBrightness,
+                rawPolicy.enableDataSaver,
+                rawPolicy.enableFirewall,
+                // Don't force night mode when car projection is enabled.
+                rawPolicy.enableNightMode && !mCarModeEnabled,
+                rawPolicy.enableQuickDoze,
+                rawPolicy.filesForInteractive,
+                rawPolicy.filesForNoninteractive,
+                rawPolicy.forceAllAppsStandby,
+                rawPolicy.forceBackgroundCheck,
+                locationMode
+        );
+
 
         final StringBuilder sb = new StringBuilder();
 
-        if (currPolicy.forceAllAppsStandby) sb.append("A");
-        if (currPolicy.forceBackgroundCheck) sb.append("B");
+        if (mEffectivePolicy.forceAllAppsStandby) sb.append("A");
+        if (mEffectivePolicy.forceBackgroundCheck) sb.append("B");
 
-        if (mDisableVibrationEffective) sb.append("v");
-        if (currPolicy.disableAnimation) sb.append("a");
-        if (currPolicy.disableSoundTrigger) sb.append("s");
-        if (currPolicy.deferFullBackup) sb.append("F");
-        if (currPolicy.deferKeyValueBackup) sb.append("K");
-        if (currPolicy.enableFirewall) sb.append("f");
-        if (currPolicy.enableDataSaver) sb.append("d");
-        if (currPolicy.enableAdjustBrightness) sb.append("b");
+        if (mEffectivePolicy.disableVibration) sb.append("v");
+        if (mEffectivePolicy.disableAnimation) sb.append("a");
+        if (mEffectivePolicy.disableSoundTrigger) sb.append("s");
+        if (mEffectivePolicy.deferFullBackup) sb.append("F");
+        if (mEffectivePolicy.deferKeyValueBackup) sb.append("K");
+        if (mEffectivePolicy.enableFirewall) sb.append("f");
+        if (mEffectivePolicy.enableDataSaver) sb.append("d");
+        if (mEffectivePolicy.enableAdjustBrightness) sb.append("b");
 
-        if (currPolicy.disableLaunchBoost) sb.append("l");
-        if (currPolicy.disableOptionalSensors) sb.append("S");
-        if (currPolicy.disableAod) sb.append("o");
-        if (currPolicy.enableQuickDoze) sb.append("q");
+        if (mEffectivePolicy.disableLaunchBoost) sb.append("l");
+        if (mEffectivePolicy.disableOptionalSensors) sb.append("S");
+        if (mEffectivePolicy.disableAod) sb.append("o");
+        if (mEffectivePolicy.enableQuickDoze) sb.append("q");
 
-        sb.append(currPolicy.locationMode);
+        sb.append(mEffectivePolicy.locationMode);
 
         mEventLogKeys = sb.toString();
     }
@@ -857,7 +935,7 @@
                     return builder.setBatterySaverEnabled(currPolicy.disableSoundTrigger)
                             .build();
                 case ServiceType.VIBRATION:
-                    return builder.setBatterySaverEnabled(mDisableVibrationEffective)
+                    return builder.setBatterySaverEnabled(currPolicy.disableVibration)
                             .build();
                 case ServiceType.FORCE_ALL_APPS_STANDBY:
                     return builder.setBatterySaverEnabled(currPolicy.forceAllAppsStandby)
@@ -933,6 +1011,10 @@
     }
 
     private Policy getCurrentPolicyLocked() {
+        return mEffectivePolicy;
+    }
+
+    private Policy getCurrentRawPolicyLocked() {
         switch (getPolicyLevelLocked()) {
             case POLICY_LEVEL_FULL:
                 return mFullPolicy;
@@ -994,11 +1076,13 @@
             pw.println("    value: " + mAdaptiveDeviceSpecificSettings);
 
             pw.println("  mAccessibilityEnabled=" + mAccessibilityEnabled);
+            pw.println("  mCarModeEnabled=" + mCarModeEnabled);
             pw.println("  mPolicyLevel=" + getPolicyLevelLocked());
 
             dumpPolicyLocked(pw, "  ", "full", mFullPolicy);
             dumpPolicyLocked(pw, "  ", "default adaptive", mDefaultAdaptivePolicy);
             dumpPolicyLocked(pw, "  ", "current adaptive", mAdaptivePolicy);
+            dumpPolicyLocked(pw, "  ", "effective", mEffectivePolicy);
         }
     }
 
@@ -1009,11 +1093,7 @@
         pw.print(indent);
         pw.println("  " + KEY_ADVERTISE_IS_ENABLED + "=" + p.advertiseIsEnabled);
         pw.print(indent);
-        pw.println("  " + KEY_VIBRATION_DISABLED + ":config=" + p.disableVibration);
-        // mDisableVibrationEffective is based on the currently selected policy
-        pw.print(indent);
-        pw.println("  " + KEY_VIBRATION_DISABLED + ":effective=" + (p.disableVibration
-                && !mAccessibilityEnabled));
+        pw.println("  " + KEY_VIBRATION_DISABLED + "=" + p.disableVibration);
         pw.print(indent);
         pw.println("  " + KEY_ANIMATION_DISABLED + "=" + p.disableAnimation);
         pw.print(indent);
@@ -1070,10 +1150,24 @@
     }
 
     @VisibleForTesting
-    public void setAccessibilityEnabledForTest(boolean enabled) {
+    void setAccessibilityEnabled(boolean enabled) {
         synchronized (mLock) {
-            mAccessibilityEnabled = enabled;
-            updatePolicyDependenciesLocked();
+            if (mAccessibilityEnabled != enabled) {
+                mAccessibilityEnabled = enabled;
+                updatePolicyDependenciesLocked();
+                maybeNotifyListenersOfPolicyChange();
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void setCarModeEnabled(boolean enabled) {
+        synchronized (mLock) {
+            if (mCarModeEnabled != enabled) {
+                mCarModeEnabled = enabled;
+                updatePolicyDependenciesLocked();
+                maybeNotifyListenersOfPolicyChange();
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 68a7188..4fea36c 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -275,8 +275,9 @@
         }
 
         /** @return {@code true} if the activity matches a launched activity in this transition. */
-        boolean contains(ActivityRecord r) {
-            return r == mLastLaunchedActivity || mPendingDrawActivities.contains(r);
+        boolean contains(WindowContainer wc) {
+            final ActivityRecord r = AppTransitionController.getAppFromContainer(wc);
+            return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r));
         }
 
         /** Called when the activity is drawn or won't be drawn. */
@@ -435,10 +436,10 @@
 
     /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
     @Nullable
-    private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
+    private TransitionInfo getActiveTransitionInfo(WindowContainer wc) {
         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
             final TransitionInfo info = mTransitionInfoList.get(i);
-            if (info.contains(r)) {
+            if (info.contains(wc)) {
                 return info;
             }
         }
@@ -623,19 +624,19 @@
      * @param activityToReason A map from activity to a reason integer, which must be on of
      *                         ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
      */
-    void notifyTransitionStarting(ArrayMap<ActivityRecord, Integer> activityToReason) {
+    void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) {
         if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
 
         final long timestampNs = SystemClock.elapsedRealtimeNanos();
         for (int index = activityToReason.size() - 1; index >= 0; index--) {
-            final ActivityRecord r = activityToReason.keyAt(index);
-            final TransitionInfo info = getActiveTransitionInfo(r);
+            final WindowContainer wc = activityToReason.keyAt(index);
+            final TransitionInfo info = getActiveTransitionInfo(wc);
             if (info == null || info.mLoggedTransitionStarting) {
                 // Ignore any subsequent notifyTransitionStarting.
                 continue;
             }
             if (DEBUG_METRICS) {
-                Slog.i(TAG, "notifyTransitionStarting activity=" + r + " info=" + info);
+                Slog.i(TAG, "notifyTransitionStarting activity=" + wc + " info=" + info);
             }
 
             info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d715ed4..76bc366 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -40,7 +40,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.activityTypeToString;
@@ -106,7 +105,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_UNSET;
@@ -284,7 +282,6 @@
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
 import android.view.InputApplicationHandle;
-import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -577,12 +574,6 @@
      */
     private boolean mCurrentLaunchCanTurnScreenOn = true;
 
-    /**
-     * This leash is used to "freeze" the app surface in place after the state change, but before
-     * the animation is ready to start.
-     */
-    private SurfaceControl mTransitChangeLeash = null;
-
     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
     private boolean mLastSurfaceShowing = true;
 
@@ -1329,15 +1320,6 @@
             mDisplayContent.executeAppTransition();
         }
 
-        if (prevDc.mChangingApps.remove(this)) {
-            // This gets called *after* the ActivityRecord has been reparented to the new display.
-            // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
-            // so this token is now "frozen" while waiting for the animation to start on prevDc
-            // (which will be cancelled since the window is no-longer a child). However, since this
-            // is no longer a child of prevDc, this won't be notified of the cancelled animation,
-            // so we need to cancel the change transition here.
-            clearChangeLeash(getPendingTransaction(), true /* cancel */);
-        }
         prevDc.mClosingApps.remove(this);
 
         if (prevDc.mFocusedApp == this) {
@@ -3092,7 +3074,7 @@
         commitVisibility(false /* visible */, true /* performLayout */);
 
         getDisplayContent().mOpeningApps.remove(this);
-        getDisplayContent().mChangingApps.remove(this);
+        getDisplayContent().mChangingContainers.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
         mWmService.mTaskSnapshotController.onAppRemoved(this);
         mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
@@ -3995,13 +3977,11 @@
                 appToken, visible, appTransition, isVisible(), mVisibleRequested,
                 Debug.getCallers(6));
 
+        onChildVisibilityRequested(visible);
+
         final DisplayContent displayContent = getDisplayContent();
         displayContent.mOpeningApps.remove(this);
         displayContent.mClosingApps.remove(this);
-        if (isInChangeTransition()) {
-            clearChangeLeash(getPendingTransaction(), true /* cancel */);
-        }
-        displayContent.mChangingApps.remove(this);
         waitingToShow = false;
         mVisibleRequested = visible;
         mLastDeferHidingClient = deferHidingClient;
@@ -4198,13 +4178,6 @@
         final DisplayContent displayContent = getDisplayContent();
         if (!displayContent.mClosingApps.contains(this)
                 && !displayContent.mOpeningApps.contains(this)) {
-            // The token is not closing nor opening, so even if there is an animation set, that
-            // doesn't mean that it goes through the normal app transition cycle so we have
-            // to inform the docked controller about visibility change.
-            // TODO(multi-display): notify docked divider on all displays where visibility was
-            // affected.
-            displayContent.getDockedDividerController().notifyAppVisibilityChanged();
-
             // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
             // will not be taken.
             mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
@@ -5805,11 +5778,6 @@
         return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
     }
 
-    @Override
-    boolean isChangingAppTransition() {
-        return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition();
-    }
-
     /**
      * Creates a layer to apply crop to an animation.
      */
@@ -5830,84 +5798,19 @@
                 this, endDeferFinishCallback);
     }
 
-    private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
-        if (mWmService.mDisableTransitionAnimation
-                || !isVisible()
-                || getDisplayContent().mAppTransition.isTransitionSet()
-                || getSurfaceControl() == null) {
-            return false;
-        }
-        // Only do an animation into and out-of freeform mode for now. Other mode
-        // transition animations are currently handled by system-ui.
-        return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
-    }
-
     @Override
     boolean isWaitingForTransitionStart() {
         final DisplayContent dc = getDisplayContent();
         return dc != null && dc.mAppTransition.isTransitionSet()
                 && (dc.mOpeningApps.contains(this)
                 || dc.mClosingApps.contains(this)
-                || dc.mChangingApps.contains(this));
+                || dc.mChangingContainers.contains(this));
     }
 
-    /**
-     * Initializes a change transition. Because the app is visible already, there is a small period
-     * of time where the user can see the app content/window update before the transition starts.
-     * To prevent this, we immediately take a snapshot and place the app/snapshot into a leash which
-     * "freezes" the location/crop until the transition starts.
-     * <p>
-     * Here's a walk-through of the process:
-     * 1. Create a temporary leash ("interim-change-leash") and reparent the app to it.
-     * 2. Set the temporary leash's position/crop to the current state.
-     * 3. Create a snapshot and place that at the top of the leash to cover up content changes.
-     * 4. Once the transition is ready, it will reparent the app to the animation leash.
-     * 5. Detach the interim-change-leash.
-     */
-    private void initializeChangeTransition(Rect startBounds) {
-        mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
-                false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
-        mDisplayContent.mChangingApps.add(this);
-        mTransitStartRect.set(startBounds);
-
-        final SurfaceControl.Builder builder = makeAnimationLeash()
-                .setParent(getAnimationLeashParent())
-                .setName(getSurfaceControl() + " - interim-change-leash");
-        mTransitChangeLeash = builder.build();
-        Transaction t = getPendingTransaction();
-        t.setWindowCrop(mTransitChangeLeash, startBounds.width(), startBounds.height());
-        t.setPosition(mTransitChangeLeash, startBounds.left, startBounds.top);
-        t.show(mTransitChangeLeash);
-        t.reparent(getSurfaceControl(), mTransitChangeLeash);
-        onAnimationLeashCreated(t, mTransitChangeLeash);
-
-        // Skip creating snapshot if this transition is controlled by a remote animator which
-        // doesn't need it.
-        ArraySet<Integer> activityTypes = new ArraySet<>();
-        activityTypes.add(getActivityType());
-        RemoteAnimationAdapter adapter =
-                mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
-                        this, TRANSIT_TASK_CHANGE_WINDOWING_MODE, activityTypes);
-        if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
-            return;
-        }
-
-        if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) {
-            SurfaceControl.ScreenshotGraphicBuffer snapshot =
-                    mWmService.mTaskSnapshotController.createTaskSnapshot(
-                            task, 1 /* scaleFraction */);
-            if (snapshot != null) {
-                mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, t, this,
-                        snapshot.getGraphicBuffer(), true /* relative */);
-            }
-        }
-    }
-
-    @Override
-    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+    private int getAnimationLayer() {
         // The leash is parented to the animation layer. We need to preserve the z-order by using
         // the prefix order index, but we boost if necessary.
-        int layer = 0;
+        int layer;
         if (!inPinnedWindowingMode()) {
             layer = getPrefixOrderIndex();
         } else {
@@ -5920,21 +5823,17 @@
         if (mNeedsZBoost) {
             layer += Z_BOOST_BASE;
         }
-        if (!mNeedsAnimationBoundsLayer) {
-            t.setLayer(leash, layer);
-        }
+        return layer;
+    }
 
-        final DisplayContent dc = getDisplayContent();
-        dc.assignStackOrdering();
+    @Override
+    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+        t.setLayer(leash, getAnimationLayer());
+        getDisplayContent().assignStackOrdering();
+    }
 
-        if (leash == mTransitChangeLeash) {
-            // This is a temporary state so skip any animation notifications
-            return;
-        } else if (mTransitChangeLeash != null) {
-            // unparent mTransitChangeLeash for clean-up
-            clearChangeLeash(t, false /* cancel */);
-        }
-
+    @Override
+    public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
         if (mAnimatingActivityRegistry != null) {
             mAnimatingActivityRegistry.notifyStarting(this);
         }
@@ -5962,7 +5861,8 @@
                 // surface size has already same as the animating container.
                 t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
             }
-            t.setLayer(mAnimationBoundsLayer, layer);
+            t.setLayer(leash, 0);
+            t.setLayer(mAnimationBoundsLayer, getAnimationLayer());
 
             // Reparent leash to animation bounds layer.
             t.reparent(leash, mAnimationBoundsLayer);
@@ -5994,10 +5894,6 @@
         return mLastSurfaceShowing;
     }
 
-    boolean isInChangeTransition() {
-        return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
-    }
-
     void attachThumbnailAnimation() {
         if (!isAnimating(PARENTS)) {
             return;
@@ -6134,31 +6030,6 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
-    /**
-     * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
-     *                            to another leash.
-     */
-    private void clearChangeLeash(Transaction t, boolean cancel) {
-        if (mTransitChangeLeash == null) {
-            return;
-        }
-        if (cancel) {
-            clearThumbnail();
-            SurfaceControl sc = getSurfaceControl();
-            SurfaceControl parentSc = getParentSurfaceControl();
-            // Don't reparent if surface is getting destroyed
-            if (parentSc != null && sc != null) {
-                t.reparent(sc, getParentSurfaceControl());
-            }
-        }
-        t.hide(mTransitChangeLeash);
-        t.remove(mTransitChangeLeash);
-        mTransitChangeLeash = null;
-        if (cancel) {
-            onAnimationLeashLost(t);
-        }
-    }
-
     void clearAnimatingFlags() {
         boolean wallpaperMightChange = false;
         for (int i = mChildren.size() - 1; i >= 0; i--) {
@@ -6174,7 +6045,7 @@
     void cancelAnimation() {
         cancelAnimationOnly();
         clearThumbnail();
-        clearChangeLeash(getPendingTransaction(), true /* cancel */);
+        mSurfaceFreezer.unfreeze(getPendingTransaction());
     }
 
     /**
@@ -6219,6 +6090,7 @@
         mRemoteAnimationDefinition = null;
     }
 
+    @Override
     RemoteAnimationDefinition getRemoteAnimationDefinition() {
         return mRemoteAnimationDefinition;
     }
@@ -6679,8 +6551,6 @@
                 return;
             }
         }
-        final int prevWinMode = getWindowingMode();
-        mTmpPrevBounds.set(getBounds());
         super.onConfigurationChanged(newParentConfig);
 
         if (shouldUseSizeCompatMode()) {
@@ -6705,12 +6575,6 @@
             }
         }
 
-        final int newWinMode = getWindowingMode();
-        if ((prevWinMode != newWinMode) && (mDisplayContent != null)
-                && shouldStartChangeTransition(prevWinMode, newWinMode)) {
-            initializeChangeTransition(mTmpPrevBounds);
-        }
-
         // Configuration's equality doesn't consider seq so if only seq number changes in resolved
         // override configuration. Therefore ConfigurationContainer doesn't change merged override
         // configuration, but it's used to push configuration changes so explicitly update that.
@@ -7595,6 +7459,7 @@
         }
     }
 
+    @Override
     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ff890ff..598389b 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -17,8 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
@@ -39,16 +37,10 @@
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
@@ -98,13 +90,8 @@
 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.TaskProto.ACTIVITIES;
 import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
-import static com.android.server.wm.TaskProto.ADJUSTED_BOUNDS;
-import static com.android.server.wm.TaskProto.ADJUSTED_FOR_IME;
-import static com.android.server.wm.TaskProto.ADJUST_DIVIDER_AMOUNT;
-import static com.android.server.wm.TaskProto.ADJUST_IME_AMOUNT;
 import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
 import static com.android.server.wm.TaskProto.BOUNDS;
 import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
@@ -113,7 +100,6 @@
 import static com.android.server.wm.TaskProto.DISPLAY_ID;
 import static com.android.server.wm.TaskProto.FILLS_PARENT;
 import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
-import static com.android.server.wm.TaskProto.MINIMIZE_AMOUNT;
 import static com.android.server.wm.TaskProto.MIN_HEIGHT;
 import static com.android.server.wm.TaskProto.MIN_WIDTH;
 import static com.android.server.wm.TaskProto.ORIG_ACTIVITY;
@@ -168,7 +154,6 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
-import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.ITaskOrganizer;
 import android.view.SurfaceControl;
@@ -177,8 +162,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DockedDividerUtils;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -238,13 +221,6 @@
     /** Stack is completely invisible. */
     static final int STACK_VISIBILITY_INVISIBLE = 2;
 
-    /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
-     * restrict IME adjustment so that a min portion of top stack remains visible.*/
-    private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
-
-    /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
-    private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
-
     enum ActivityState {
         INITIALIZING,
         STARTED,
@@ -294,28 +270,10 @@
     /** For Pinned stack controlling. */
     private Rect mTmpToBounds = new Rect();
 
-    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
-    private final Rect mAdjustedBounds = new Rect();
-
-    /**
-     * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
-     * represent the state when the animation has ended.
-     */
-    private final Rect mFullyAdjustedImeBounds = new Rect();
-
     /** Detach this stack from its display when animation completes. */
     // TODO: maybe tie this to WindowContainer#removeChild some how...
     private boolean mDeferRemoval;
 
-    private final Rect mTmpAdjustedBounds = new Rect();
-    private boolean mAdjustedForIme;
-    private boolean mImeGoingAway;
-    private WindowState mImeWin;
-    private float mMinimizeAmount;
-    private float mAdjustImeAmount;
-    private float mAdjustDividerAmount;
-    private final int mDockedStackMinimizeThickness;
-
     // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
     // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
     // would otherwise apply while resizing, while resizing in the bounds animating mode.
@@ -643,8 +601,6 @@
                 _realActivitySuspended, userSetupComplete, minWidth, minHeight, info, _voiceSession,
                 _voiceInteractor, stack);
 
-        mDockedStackMinimizeThickness = mWmService.mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_minimize_thickness);
         EventLogTags.writeWmStackCreated(id);
         mHandler = new ActivityStackHandler(mStackSupervisor.mLooper);
         mCurrentUser = mAtmService.mAmInternal.getCurrentUserId();
@@ -1202,8 +1158,8 @@
 
     @Override
     boolean isFocusable() {
-        return super.isFocusable() && !(inSplitScreenPrimaryWindowingMode()
-                && mRootWindowContainer.mIsDockMinimized);
+        // Special check for tile which isn't really in the hierarchy
+        return mTile != null ? mTile.isFocusable() : super.isFocusable();
     }
 
     boolean isTopActivityFocusable() {
@@ -3497,43 +3453,6 @@
         forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */);
     }
 
-    /**
-     * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
-     * the normal task bounds.
-     *
-     * @param bounds The adjusted bounds.
-     */
-    private void setAdjustedBounds(Rect bounds) {
-        if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
-            return;
-        }
-
-        mAdjustedBounds.set(bounds);
-        final boolean adjusted = !mAdjustedBounds.isEmpty();
-        Rect insetBounds = null;
-        if (adjusted && isAdjustedForMinimizedDockedStack()) {
-            insetBounds = getRawBounds();
-        } else if (adjusted && mAdjustedForIme) {
-            if (mImeGoingAway) {
-                insetBounds = getRawBounds();
-            } else {
-                insetBounds = mFullyAdjustedImeBounds;
-            }
-        }
-
-        if (!matchParentBounds()) {
-            final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
-            final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds,
-                    PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(),
-                    insetBounds, alignBottom);
-            forAllLeafTasks(c, true /* traverseTopToBottom */);
-            c.recycle();
-        }
-
-        mDisplayContent.setLayoutNeeded();
-        updateSurfaceBounds();
-    }
-
     @Override
     public int setBounds(Rect bounds) {
         // Calling Task#setBounds() for leaf task since this is the a specialization of
@@ -3552,8 +3471,6 @@
 
         final int result = super.setBounds(!inMultiWindowMode() ? null : bounds);
 
-        updateAdjustedBounds();
-
         updateSurfaceBounds();
         return result;
     }
@@ -3575,19 +3492,6 @@
         bounds.set(getBounds());
     }
 
-    @Override
-    public Rect getBounds() {
-        // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
-        // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
-        // stack is visible since it is already what we want to represent to the rest of the
-        // system.
-        if (!mAdjustedBounds.isEmpty()) {
-            return mAdjustedBounds;
-        } else {
-            return super.getBounds();
-        }
-    }
-
     /**
      * @return the final bounds for the bounds animation.
      */
@@ -3620,113 +3524,6 @@
     }
 
     /**
-     * Updates the passed-in {@code inOutBounds} based on the current state of the
-     * docked controller. This gets run *after* the override configuration is updated, so it's
-     * safe to rely on the controller's state in here (though eventually this dependence should
-     * be removed).
-     *
-     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
-     * update docked controller state.
-     *
-     * @param parentConfig the parent configuration for reference.
-     * @param inOutBounds the bounds to update (both input and output).
-     */
-    void calculateDockedBoundsForConfigChange(Configuration parentConfig, Rect inOutBounds) {
-        final boolean primary =
-                getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-        repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds);
-        final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout;
-        snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds);
-        if (primary) {
-            final int newDockSide = getDockSide(parentConfig, inOutBounds);
-            // Update the dock create mode and clear the dock create bounds, these
-            // might change after a rotation and the original values will be invalid.
-            mWmService.setDockedStackCreateStateLocked(
-                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
-                            ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
-                            : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
-                    null);
-            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
-        }
-    }
-
-    /**
-     * Some primary split screen sides are not allowed by the policy. This method queries the policy
-     * and moves the primary stack around if needed.
-     *
-     * @param parentConfig the configuration of the stack's parent.
-     * @param primary true if adjusting the primary docked stack, false for secondary.
-     * @param inOutBounds the bounds of the stack to adjust.
-     */
-    void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary,
-            Rect inOutBounds) {
-        final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
-        final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide);
-        final int primaryDockSide = primary ? dockSide : otherDockSide;
-        if (mDisplayContent.getDockedDividerController()
-                .canPrimaryStackDockTo(primaryDockSide,
-                        parentConfig.windowConfiguration.getBounds(),
-                        parentConfig.windowConfiguration.getRotation())) {
-            return;
-        }
-        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
-        switch (otherDockSide) {
-            case DOCKED_LEFT:
-                int movement = inOutBounds.left;
-                inOutBounds.left -= movement;
-                inOutBounds.right -= movement;
-                break;
-            case DOCKED_RIGHT:
-                movement = parentBounds.right - inOutBounds.right;
-                inOutBounds.left += movement;
-                inOutBounds.right += movement;
-                break;
-            case DOCKED_TOP:
-                movement = inOutBounds.top;
-                inOutBounds.top -= movement;
-                inOutBounds.bottom -= movement;
-                break;
-            case DOCKED_BOTTOM:
-                movement = parentBounds.bottom - inOutBounds.bottom;
-                inOutBounds.top += movement;
-                inOutBounds.bottom += movement;
-                break;
-        }
-    }
-
-    /**
-     * Snaps the bounds after rotation to the closest snap target for the docked stack.
-     */
-    void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout,
-            Rect outBounds) {
-
-        // Calculate the current position.
-        final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
-        final int dockSide = getDockSide(parentConfig, outBounds);
-        final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
-                dockSide, dividerSize);
-        final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
-        final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
-
-        // Snap the position to a target.
-        final int rotation = parentConfig.windowConfiguration.getRotation();
-        final int orientation = parentConfig.orientation;
-        mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, displayWidth, displayHeight,
-                displayCutout, outBounds);
-        final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
-                mWmService.mContext.getResources(), displayWidth, displayHeight,
-                dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
-                getDockSide(), isMinimizedDockAndHomeStackResizable());
-        final DividerSnapAlgorithm.SnapTarget target =
-                algorithm.calculateNonDismissingSnapTarget(dividerPosition);
-
-        // Recalculate the bounds based on the position of the target.
-        DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
-                outBounds, displayWidth, displayHeight,
-                dividerSize);
-    }
-
-    /**
      * Put a Task in this stack. Used for adding only.
      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
      * and display) will be brought to top.
@@ -3916,445 +3713,8 @@
         }
     }
 
-    /**
-     * Determines the stack and task bounds of the other stack when in docked mode. The current task
-     * bounds is passed in but depending on the stack, the task and stack must match. Only in
-     * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds
-     * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds
-     * is calculated and is also used for its task bounds.
-     * If any of the out bounds are empty, it represents default bounds
-     *
-     * @param currentTempTaskBounds the current task bounds of the other stack
-     * @param outStackBounds the calculated stack bounds of the other stack
-     * @param outTempTaskBounds the calculated task bounds of the other stack
-     */
-    void getStackDockedModeBounds(Rect dockedBounds,
-            Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) {
-        final Configuration parentConfig = getParent().getConfiguration();
-        outTempTaskBounds.setEmpty();
-
-        if (dockedBounds == null || dockedBounds.isEmpty()) {
-            // Calculate the primary docked bounds.
-            final boolean dockedOnTopOrLeft = mWmService.mDockedStackCreateMode
-                    == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-            getStackDockedModeBounds(parentConfig,
-                    true /* primary */, outStackBounds, dockedBounds,
-                    mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
-            return;
-        }
-        final int dockedSide = getDockSide(parentConfig, dockedBounds);
-
-        // When the home stack is resizable, should always have the same stack and task bounds
-        if (isActivityTypeHome()) {
-            final Task homeTask = getTopMostTask();
-            if (homeTask == null || homeTask.isResizeable()) {
-                // Calculate the home stack bounds when in docked mode and the home stack is
-                // resizeable.
-                getDisplayContent().mDividerControllerLocked
-                        .getHomeStackBoundsInDockedMode(parentConfig,
-                                dockedSide, outStackBounds);
-            } else {
-                // Home stack isn't resizeable, so don't specify stack bounds.
-                outStackBounds.setEmpty();
-            }
-
-            outTempTaskBounds.set(outStackBounds);
-            return;
-        }
-
-        // When minimized state, the stack bounds for all non-home and docked stack bounds should
-        // match the passed task bounds
-        if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) {
-            outStackBounds.set(currentTempTaskBounds);
-            return;
-        }
-
-        if (dockedSide == DOCKED_INVALID) {
-            // Not sure how you got here...Only thing we can do is return current bounds.
-            Slog.e(TAG_WM, "Failed to get valid docked side for docked stack");
-            outStackBounds.set(getRawBounds());
-            return;
-        }
-
-        final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
-        getStackDockedModeBounds(parentConfig,
-                false /* primary */, outStackBounds, dockedBounds,
-                mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
-    }
-
-    /**
-     * Outputs the bounds a stack should be given the presence of a docked stack on the display.
-     * @param parentConfig The parent configuration.
-     * @param primary {@code true} if getting the primary stack bounds.
-     * @param outBounds Output bounds that should be used for the stack.
-     * @param dockedBounds Bounds of the docked stack.
-     * @param dockDividerWidth We need to know the width of the divider make to the output bounds
-     *                         close to the side of the dock.
-     * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
-     */
-    private void getStackDockedModeBounds(Configuration parentConfig, boolean primary,
-            Rect outBounds, Rect dockedBounds, int dockDividerWidth,
-            boolean dockOnTopOrLeft) {
-        final Rect displayRect = parentConfig.windowConfiguration.getBounds();
-        final boolean splitHorizontally = displayRect.width() > displayRect.height();
-
-        outBounds.set(displayRect);
-        if (primary) {
-            if (mWmService.mDockedStackCreateBounds != null) {
-                outBounds.set(mWmService.mDockedStackCreateBounds);
-                return;
-            }
-
-            // The initial bounds of the docked stack when it is created about half the screen space
-            // and its bounds can be adjusted after that. The bounds of all other stacks are
-            // adjusted to occupy whatever screen space the docked stack isn't occupying.
-            final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
-            mDisplayContent.getDisplayPolicy().getStableInsetsLw(
-                    parentConfig.windowConfiguration.getRotation(),
-                    displayRect.width(), displayRect.height(), displayCutout, mTmpRect2);
-            final int position = new DividerSnapAlgorithm(mWmService.mContext.getResources(),
-                    displayRect.width(),
-                    displayRect.height(),
-                    dockDividerWidth,
-                    parentConfig.orientation == ORIENTATION_PORTRAIT,
-                    mTmpRect2).getMiddleTarget().position;
-
-            if (dockOnTopOrLeft) {
-                if (splitHorizontally) {
-                    outBounds.right = position;
-                } else {
-                    outBounds.bottom = position;
-                }
-            } else {
-                if (splitHorizontally) {
-                    outBounds.left = position + dockDividerWidth;
-                } else {
-                    outBounds.top = position + dockDividerWidth;
-                }
-            }
-            return;
-        }
-
-        // Other stacks occupy whatever space is left by the docked stack.
-        if (!dockOnTopOrLeft) {
-            if (splitHorizontally) {
-                outBounds.right = dockedBounds.left - dockDividerWidth;
-            } else {
-                outBounds.bottom = dockedBounds.top - dockDividerWidth;
-            }
-        } else {
-            if (splitHorizontally) {
-                outBounds.left = dockedBounds.right + dockDividerWidth;
-            } else {
-                outBounds.top = dockedBounds.bottom + dockDividerWidth;
-            }
-        }
-        DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
-    }
-
-    void resetDockedStackToMiddle() {
-        if (!inSplitScreenPrimaryWindowingMode()) {
-            throw new IllegalStateException("Not a docked stack=" + this);
-        }
-
-        mWmService.mDockedStackCreateBounds = null;
-
-        final Rect bounds = new Rect();
-        final Rect tempBounds = new Rect();
-        getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
-                bounds, tempBounds);
-        mStackSupervisor.resizeDockedStackLocked(bounds, null /* tempTaskBounds */,
-                null /* tempTaskInsetBounds */, null /* tempOtherTaskBounds */,
-                null /* tempOtherTaskInsetBounds */, false /* preserveWindows */,
-                false /* deferResume */);
-    }
-
-    /**
-     * Adjusts the stack bounds if the IME is visible.
-     *
-     * @param imeWin The IME window.
-     * @param keepLastAmount Use {@code true} to keep the last adjusted amount from
-     *                       {@link DockedStackDividerController} for adjusting the stack bounds,
-     *                       Use {@code false} to reset adjusted amount as 0.
-     * @see #updateAdjustForIme(float, float, boolean)
-     */
-    void setAdjustedForIme(WindowState imeWin, boolean keepLastAmount) {
-        mImeWin = imeWin;
-        mImeGoingAway = false;
-        if (!mAdjustedForIme || keepLastAmount) {
-            mAdjustedForIme = true;
-            DockedStackDividerController controller = getDisplayContent().mDividerControllerLocked;
-            final float adjustImeAmount = keepLastAmount ? controller.mLastAnimationProgress : 0f;
-            final float adjustDividerAmount = keepLastAmount ? controller.mLastDividerProgress : 0f;
-            updateAdjustForIme(adjustImeAmount, adjustDividerAmount, true /* force */);
-        }
-    }
-
-    boolean isAdjustedForIme() {
-        return mAdjustedForIme;
-    }
-
-    boolean isAnimatingForIme() {
-        return mImeWin != null && mImeWin.isAnimatingLw();
-    }
-
-    /**
-     * Update the stack's bounds (crop or position) according to the IME window's
-     * current position. When IME window is animated, the bottom stack is animated
-     * together to track the IME window's current position, and the top stack is
-     * cropped as necessary.
-     *
-     * @return true if a traversal should be performed after the adjustment.
-     */
-    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
-        if (adjustAmount != mAdjustImeAmount
-                || adjustDividerAmount != mAdjustDividerAmount || force) {
-            mAdjustImeAmount = adjustAmount;
-            mAdjustDividerAmount = adjustDividerAmount;
-            updateAdjustedBounds();
-            return isVisible();
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Resets the adjustment after it got adjusted for the IME.
-     * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
-     *                        animations; otherwise, set flag and animates the window away together
-     *                        with IME window.
-     */
-    void resetAdjustedForIme(boolean adjustBoundsNow) {
-        if (adjustBoundsNow) {
-            mImeWin = null;
-            mImeGoingAway = false;
-            mAdjustImeAmount = 0f;
-            mAdjustDividerAmount = 0f;
-            if (!mAdjustedForIme) {
-                return;
-            }
-            mAdjustedForIme = false;
-            updateAdjustedBounds();
-            mWmService.setResizeDimLayer(false, getWindowingMode(), 1.0f);
-        } else {
-            mImeGoingAway |= mAdjustedForIme;
-        }
-    }
-
-    /**
-     * Sets the amount how much we currently minimize our stack.
-     *
-     * @param minimizeAmount The amount, between 0 and 1.
-     * @return Whether the amount has changed and a layout is needed.
-     */
-    boolean setAdjustedForMinimizedDock(float minimizeAmount) {
-        if (minimizeAmount != mMinimizeAmount) {
-            mMinimizeAmount = minimizeAmount;
-            updateAdjustedBounds();
-            return isVisible();
-        } else {
-            return false;
-        }
-    }
-
     boolean shouldIgnoreInput() {
-        return isAdjustedForMinimizedDockedStack()
-                || (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable());
-    }
-
-    /**
-     * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
-     * to the list of to be drawn windows the service is waiting for.
-     */
-    void beginImeAdjustAnimation() {
-        forAllLeafTasks((t) -> {
-            if (t.hasContentToDisplay()) {
-                t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-                t.setWaitingForDrawnIfResizingChanged();
-            }
-        }, true /* traverseTopToBottom */);
-    }
-
-    /** Resets the resizing state of all windows. */
-    void endImeAdjustAnimation() {
-        forAllLeafTasks((t) -> {
-            t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-        }, true /* traverseTopToBottom */);
-    }
-
-    private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
-        return displayContentRect.top + (int)
-                ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
-    }
-
-    private boolean adjustForIME(final WindowState imeWin) {
-        // To prevent task stack resize animation may flicking when playing app transition
-        // animation & IME window enter animation in parallel, we need to make sure app
-        // transition is done and then adjust task size for IME, skip the new adjusted frame when
-        // app transition is still running.
-        if (getDisplayContent().mAppTransition.isRunning()) {
-            return false;
-        }
-
-        final int dockedSide = getDockSide();
-        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
-        if (imeWin == null || !dockedTopOrBottom) {
-            return false;
-        }
-
-        final Rect displayStableRect = mTmpRect;
-        final Rect contentBounds = mTmpRect2;
-
-        // Calculate the content bounds excluding the area occupied by IME
-        getDisplayContent().getStableRect(displayStableRect);
-        contentBounds.set(displayStableRect);
-        int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
-
-        imeTop += imeWin.getGivenContentInsetsLw().top;
-        if (contentBounds.bottom > imeTop) {
-            contentBounds.bottom = imeTop;
-        }
-
-        final int yOffset = displayStableRect.bottom - contentBounds.bottom;
-
-        final int dividerWidth =
-                getDisplayContent().mDividerControllerLocked.getContentWidth();
-        final int dividerWidthInactive =
-                getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
-
-        if (dockedSide == DOCKED_TOP) {
-            // If this stack is docked on top, we make it smaller so the bottom stack is not
-            // occluded by IME. We shift its bottom up by the height of the IME, but
-            // leaves at least 30% of the top stack visible.
-            final int minTopStackBottom =
-                    getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
-            final int bottom = Math.max(
-                    getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
-                    minTopStackBottom);
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount)
-                    * getRawBounds().bottom);
-            mFullyAdjustedImeBounds.set(getRawBounds());
-        } else {
-            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
-            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
-
-            // When the stack is on bottom and has focus, it needs to be moved up so as to
-            // not occluded by IME, and at the same time adjusted for divider width.
-            // We try to move it up by the height of the IME window, but only to the extent
-            // that leaves at least 30% of the top stack visible.
-            // 'top' is where the top of bottom stack will move to in this case.
-            final int topBeforeImeAdjust =
-                    getRawBounds().top - dividerWidth + dividerWidthInactive;
-            final int minTopStackBottom =
-                    getMinTopStackBottom(displayStableRect,
-                            getRawBounds().top - dividerWidth);
-            final int top = Math.max(
-                    getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
-
-            mTmpAdjustedBounds.set(getRawBounds());
-            // Account for the adjustment for IME and divider width separately.
-            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
-            // and dividerWidthDelta is due to divider width change only.
-            mTmpAdjustedBounds.top =
-                    getRawBounds().top + (int) (mAdjustImeAmount * (top - topBeforeImeAdjust)
-                            + mAdjustDividerAmount * dividerWidthDelta);
-            mFullyAdjustedImeBounds.set(getRawBounds());
-            mFullyAdjustedImeBounds.top = top;
-            mFullyAdjustedImeBounds.bottom = top + getRawBounds().height();
-        }
-        return true;
-    }
-
-    private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
-        final int dockSide = getDockSide();
-        if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
-            return false;
-        }
-
-        if (dockSide == DOCKED_TOP) {
-            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
-            int topInset = mTmpRect.top;
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount)
-                    * getRawBounds().bottom);
-        } else if (dockSide == DOCKED_LEFT) {
-            mTmpAdjustedBounds.set(getRawBounds());
-            final int width = getRawBounds().width();
-            mTmpAdjustedBounds.right =
-                    (int) (minimizeAmount * mDockedStackMinimizeThickness
-                            + (1 - minimizeAmount) * getRawBounds().right);
-            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
-        } else if (dockSide == DOCKED_RIGHT) {
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.left =
-                    (int) (minimizeAmount * (getRawBounds().right - mDockedStackMinimizeThickness)
-                            + (1 - minimizeAmount) * getRawBounds().left);
-        }
-        return true;
-    }
-
-    boolean isMinimizedDockAndHomeStackResizable() {
-        return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
-                && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
-    }
-
-    /**
-     * @return the distance in pixels how much the stack gets minimized from it's original size
-     */
-    int getMinimizeDistance() {
-        final int dockSide = getDockSide();
-        if (dockSide == DOCKED_INVALID) {
-            return 0;
-        }
-
-        if (dockSide == DOCKED_TOP) {
-            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
-            int topInset = mTmpRect.top;
-            return getRawBounds().bottom - topInset;
-        } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
-            return getRawBounds().width() - mDockedStackMinimizeThickness;
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Updates the adjustment depending on it's current state.
-     */
-    private void updateAdjustedBounds() {
-        boolean adjust = false;
-        if (mMinimizeAmount != 0f) {
-            adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
-        } else if (mAdjustedForIme) {
-            adjust = adjustForIME(mImeWin);
-        }
-        if (!adjust) {
-            mTmpAdjustedBounds.setEmpty();
-        }
-        setAdjustedBounds(mTmpAdjustedBounds);
-
-        final boolean isImeTarget = (mWmService.getImeFocusStackLocked() == this);
-        if (mAdjustedForIme && adjust && !isImeTarget) {
-            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
-                    * IME_ADJUST_DIM_AMOUNT;
-            mWmService.setResizeDimLayer(true, getWindowingMode(), alpha);
-        }
-    }
-
-    void applyAdjustForImeIfNeeded(Task task) {
-        if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
-            return;
-        }
-
-        final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds;
-        task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
-        mDisplayContent.setLayoutNeeded();
-    }
-
-
-    boolean isAdjustedForMinimizedDockedStack() {
-        return mMinimizeAmount != 0f;
+        return inSplitScreenPrimaryWindowingMode() && !isFocusable();
     }
 
     @Override
@@ -4362,17 +3722,6 @@
         pw.println(prefix + "mStackId=" + getRootTaskId());
         pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
         pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
-        if (mMinimizeAmount != 0f) {
-            pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
-        }
-        if (mAdjustedForIme) {
-            pw.println(prefix + "mAdjustedForIme=true");
-            pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
-            pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
-        }
-        if (!mAdjustedBounds.isEmpty()) {
-            pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
-        }
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
             mChildren.get(taskNdx).dump(pw, prefix + "  ", dumpAll);
         }
@@ -4391,39 +3740,6 @@
     }
 
     /**
-     * For docked workspace (or workspace that's side-by-side to the docked), provides
-     * information which side of the screen was the dock anchored.
-     */
-    int getDockSide() {
-        return getDockSide(mDisplayContent.getConfiguration(), getRawBounds());
-    }
-
-    int getDockSideForDisplay(DisplayContent dc) {
-        return getDockSide(dc, dc.getConfiguration(), getRawBounds());
-    }
-
-    int getDockSide(Configuration parentConfig, Rect bounds) {
-        if (mDisplayContent == null) {
-            return DOCKED_INVALID;
-        }
-        return getDockSide(mDisplayContent, parentConfig, bounds);
-    }
-
-    private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) {
-        return dc.getDockedDividerController().getDockSide(bounds,
-                parentConfig.windowConfiguration.getBounds(),
-                parentConfig.orientation, parentConfig.windowConfiguration.getRotation());
-    }
-
-    boolean hasTaskForUser(int userId) {
-        final PooledPredicate p = PooledLambda.obtainPredicate(
-                Task::isTaskForUser, PooledLambda.__(Task.class), userId);
-        final Task task = getTask(p);
-        p.recycle();
-        return task != null;
-    }
-
-    /**
      * Sets the current picture-in-picture aspect ratio.
      */
     void setPictureInPictureAspectRatio(float aspectRatio) {
@@ -4639,16 +3955,11 @@
             bounds.dumpDebug(proto, BOUNDS);
         }
         getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS);
-        mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS);
         if (mLastNonFullscreenBounds != null) {
             mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
         }
 
         proto.write(DEFER_REMOVAL, mDeferRemoval);
-        proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
-        proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
-        proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
-        proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
         proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
 
         if (mSurfaceControl != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index b2d2f62..6d7f8fb 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -35,12 +35,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.graphics.Rect.copyOrNull;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
@@ -210,17 +208,6 @@
     /** True if the docked stack is currently being resized. */
     private boolean mDockedStackResizing;
 
-    /**
-     * True if there are pending docked bounds that need to be applied after
-     * {@link #mDockedStackResizing} is reset to false.
-     */
-    private boolean mHasPendingDockedBounds;
-    private Rect mPendingDockedBounds;
-    private Rect mPendingTempDockedTaskBounds;
-    private Rect mPendingTempDockedTaskInsetBounds;
-    private Rect mPendingTempOtherTaskBounds;
-    private Rect mPendingTempOtherTaskInsetBounds;
-
     // Activity actions an app cannot start if it uses a permission which is not granted.
     private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
             new ArrayMap<>();
@@ -387,15 +374,6 @@
      */
     private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();
 
-
-    /**
-     * If set to {@code false} all calls to resize the docked stack {@link #resizeDockedStackLocked}
-     * will be ignored. Useful for the case where the caller is handling resizing of other stack and
-     * moving tasks around and doesn't want dock stack to be resized due to an automatic trigger
-     * like the docked stack going empty.
-     */
-    private boolean mAllowDockedStackResize = true;
-
     private KeyguardController mKeyguardController;
 
     private PowerManager mPowerManager;
@@ -1541,12 +1519,6 @@
                     }
                     otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
                 }
-
-                // Also disable docked stack resizing since we have manually adjusted the
-                // size of other stacks above and we don't want to trigger a docked stack
-                // resize when we remove task from it below and it is detached from the
-                // display because it no longer contains any tasks.
-                mAllowDockedStackResize = false;
             }
 
             // If we are moving from the pinned stack, then the animation takes care of updating
@@ -1563,7 +1535,6 @@
             mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
             mRootWindowContainer.resumeFocusedStacksTopActivities();
         } finally {
-            mAllowDockedStackResize = true;
             mService.continueWindowLayout();
         }
     }
@@ -1580,120 +1551,6 @@
 
         mDockedStackResizing = resizing;
         mWindowManager.setDockedStackResizing(resizing);
-
-        if (!resizing && mHasPendingDockedBounds) {
-            resizeDockedStackLocked(mPendingDockedBounds, mPendingTempDockedTaskBounds,
-                    mPendingTempDockedTaskInsetBounds, mPendingTempOtherTaskBounds,
-                    mPendingTempOtherTaskInsetBounds, PRESERVE_WINDOWS);
-
-            mHasPendingDockedBounds = false;
-            mPendingDockedBounds = null;
-            mPendingTempDockedTaskBounds = null;
-            mPendingTempDockedTaskInsetBounds = null;
-            mPendingTempOtherTaskBounds = null;
-            mPendingTempOtherTaskInsetBounds = null;
-        }
-    }
-
-    void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
-            Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
-            boolean preserveWindows) {
-        resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
-                tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows,
-                false /* deferResume */);
-    }
-
-    void resizeDockedStackLocked(Rect displayedBounds, Rect tempDockedTaskBounds,
-            Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds,
-            boolean preserveWindows, boolean deferResume) {
-
-        if (!mAllowDockedStackResize) {
-            // Docked stack resize currently disabled.
-            return;
-        }
-
-        final ActivityStack stack =
-                mRootWindowContainer.getDefaultDisplay().getRootSplitScreenPrimaryTask();
-        if (stack == null) {
-            Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
-            return;
-        }
-
-        if (mDockedStackResizing) {
-            mHasPendingDockedBounds = true;
-            mPendingDockedBounds = copyOrNull(displayedBounds);
-            mPendingTempDockedTaskBounds = copyOrNull(tempDockedTaskBounds);
-            mPendingTempDockedTaskInsetBounds = copyOrNull(tempDockedTaskInsetBounds);
-            mPendingTempOtherTaskBounds = copyOrNull(tempOtherTaskBounds);
-            mPendingTempOtherTaskInsetBounds = copyOrNull(tempOtherTaskInsetBounds);
-        }
-
-        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeDockedStack");
-        mService.deferWindowLayout();
-        try {
-            // Don't allow re-entry while resizing. E.g. due to docked stack detaching.
-            mAllowDockedStackResize = false;
-            ActivityRecord r = stack.topRunningActivity();
-            stack.resize(displayedBounds, tempDockedTaskBounds,
-                    !PRESERVE_WINDOWS, DEFER_RESUME);
-
-            // TODO: Checking for isAttached might not be needed as if the user passes in null
-            // dockedBounds then they want the docked stack to be dismissed.
-            if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
-                    || (displayedBounds == null && !stack.isAttached())) {
-                // The dock stack either was dismissed or went fullscreen, which is kinda the same.
-                // In this case we make all other static stacks fullscreen and move all
-                // docked stack tasks to the fullscreen stack.
-                moveTasksToFullscreenStackLocked(stack, ON_TOP);
-
-                // stack shouldn't contain anymore activities, so nothing to resume.
-                r = null;
-            } else {
-                // Docked stacks occupy a dedicated region on screen so the size of all other
-                // static stacks need to be adjusted so they don't overlap with the docked stack.
-                // We get the bounds to use from window manager which has been adjusted for any
-                // screen controls and is also the same for all stacks.
-                final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
-                final Rect otherTaskRect = new Rect();
-                for (int i = display.getStackCount() - 1; i >= 0; --i) {
-                    final ActivityStack current = display.getStackAt(i);
-                    if (!current.inSplitScreenSecondaryWindowingMode()) {
-                        continue;
-                    }
-                    if (!current.affectedBySplitScreenResize()) {
-                        continue;
-                    }
-                    if (mDockedStackResizing && !current.isTopActivityVisible()) {
-                        // Non-visible stacks get resized once we're done with the resize
-                        // interaction.
-                        continue;
-                    }
-                    current.getStackDockedModeBounds(displayedBounds,
-                            tempOtherTaskBounds /* currentTempTaskBounds */,
-                            tempRect /* outStackBounds */,
-                            otherTaskRect /* outTempTaskBounds */);
-
-                    if (tempRect.isEmpty()) {
-                        // If this scenario is hit, it means something is not working right.
-                        // Empty/null bounds implies fullscreen. In the event that this stack
-                        // *should* be fullscreen, its mode should be set explicitly in a form
-                        // of setWindowingMode so that other parts of the system are updated
-                        // properly.
-                        throw new IllegalArgumentException("Trying to set null bounds on a"
-                                + " non-fullscreen stack");
-                    }
-
-                    current.resize(tempRect, tempOtherTaskBounds, preserveWindows, deferResume);
-                }
-            }
-            if (!deferResume) {
-                stack.ensureVisibleActivitiesConfiguration(r, preserveWindows);
-            }
-        } finally {
-            mAllowDockedStackResize = true;
-            mService.continueWindowLayout();
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-        }
     }
 
     private void removeStackInSurfaceTransaction(ActivityStack stack) {
@@ -2723,9 +2580,6 @@
         mService.deferWindowLayout();
         try {
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                mWindowManager.setDockedStackCreateStateLocked(
-                        activityOptions.getSplitScreenCreateMode(), null /* initialBounds */);
-
                 // Defer updating the stack in which recents is until the app transition is done, to
                 // not run into issues where we still need to draw the task in recents but the
                 // docked stack is already created.
@@ -2801,24 +2655,6 @@
                 // the window renders full-screen with the background filling the void. Also only
                 // call this at the end to make sure that tasks exists on the window manager side.
                 setResizingDuringAnimation(task);
-
-                final DisplayContent display = task.getStack().getDisplay();
-                final ActivityStack topSecondaryStack =
-                        display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-                if (topSecondaryStack != null && topSecondaryStack.isActivityTypeHome()) {
-                    // If the home activity is the top split-screen secondary stack, then the
-                    // primary split-screen stack is in the minimized mode which means it can't
-                    // receive input keys, so we should move the focused app to the home app so that
-                    // window manager can correctly calculate the focus window that can receive
-                    // input keys.
-                    display.moveHomeActivityToTop(
-                            "startActivityFromRecents: homeVisibleInSplitScreen");
-
-                    // Immediately update the minimized docked stack mode, the upcoming animation
-                    // for the docked activity (WMS.overridePendingAppTransitionMultiThumbFuture)
-                    // will do the animation to the target bounds
-                    mWindowManager.checkSplitScreenMinimizedChanged(false /* animate */);
-                }
             }
             mService.continueWindowLayout();
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 510072d..ca856ca 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -169,12 +169,6 @@
     public abstract List<IBinder> getTopVisibleActivities();
 
     /**
-     * Callback for window manager to let activity manager know that docked stack changes its
-     * minimized state.
-     */
-    public abstract void notifyDockedStackMinimizedChanged(boolean minimized);
-
-    /**
      * Notify listeners that contents are drawn for the first time on a single task display.
      *
      * @param displayId An ID of the display on which contents are drawn.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 693a5e4..770dabf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -31,12 +31,12 @@
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -2309,9 +2309,7 @@
     @Override
     public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
         if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            return setTaskWindowingModeSplitScreenPrimary(taskId,
-                    SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
-                    toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
+            return setTaskWindowingModeSplitScreenPrimary(taskId, toTop);
         }
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
         synchronized (mGlobalLock) {
@@ -2681,10 +2679,6 @@
                     throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
                             + taskId + " to stack " + stackId);
                 }
-                if (stack.inSplitScreenPrimaryWindowingMode()) {
-                    mWindowManager.setDockedStackCreateStateLocked(
-                            SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
-                }
                 task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
                         "moveTaskToStack");
             } finally {
@@ -2697,22 +2691,11 @@
      * Moves the specified task to the primary-split-screen stack.
      *
      * @param taskId Id of task to move.
-     * @param createMode The mode the primary split screen stack should be created in if it doesn't
-     *                   exist already. See
-     *                   {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
-     *                   and
-     *                   {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
      * @param toTop If the task and stack should be moved to the top.
-     * @param animate Whether we should play an animation for the moving the task.
-     * @param initialBounds If the primary stack gets created, it will use these bounds for the
-     *                      stack. Pass {@code null} to use default bounds.
-     * @param showRecents If the recents activity should be shown on the other side of the task
-     *                    going into split-screen mode.
      * @return Whether the task was successfully put into splitscreen.
      */
     @Override
-    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
-            boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) {
+    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "setTaskWindowingModeSplitScreenPrimary()");
         synchronized (mGlobalLock) {
@@ -4273,6 +4256,7 @@
         }
     }
 
+    // TODO(b/149338177): remove when CTS no-longer requires it
     @Override
     public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds,
@@ -4281,9 +4265,42 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds,
-                        tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds,
-                        PRESERVE_WINDOWS);
+                final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
+                TaskTile primary = null;
+                TaskTile secondary = null;
+                for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+                    final TaskTile t = dc.getStackAt(i).asTile();
+                    if (t == null) {
+                        continue;
+                    }
+                    if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                        primary = t;
+                    } else if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+                        secondary = t;
+                    }
+                }
+                if (primary == null || secondary == null) {
+                    return;
+                }
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                final Rect primaryRect =
+                        tempDockedTaskInsetBounds != null ? tempDockedTaskInsetBounds
+                            : (tempDockedTaskBounds != null ? tempDockedTaskBounds
+                                    : dockedBounds);
+                wct.setBounds(primary.mRemoteToken, primaryRect);
+                Rect otherRect = tempOtherTaskInsetBounds != null ? tempOtherTaskInsetBounds
+                        : tempOtherTaskBounds;
+                if (otherRect == null) {
+                    // Temporary estimation... again this is just for tests.
+                    otherRect = new Rect(secondary.getBounds());
+                    if (dc.getBounds().width() > dc.getBounds().height()) {
+                        otherRect.left = primaryRect.right + 6;
+                    } else {
+                        otherRect.top = primaryRect.bottom + 6;
+                    }
+                }
+                wct.setBounds(secondary.mRemoteToken, otherRect);
+                mTaskOrganizerController.applyContainerTransaction(wct, null /* organizer */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -5868,8 +5885,8 @@
      * Return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME} to resolve secondary home
      * activities.
      *
-     * @param preferredPackage Specify a preferred package name, otherwise use secondary home
-     *                        component defined in config_secondaryHomeComponent.
+     * @param preferredPackage Specify a preferred package name, otherwise use the package name
+     *                         defined in config_secondaryHomePackage.
      * @return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME}
      */
     Intent getSecondaryHomeIntent(String preferredPackage) {
@@ -5877,10 +5894,10 @@
         final boolean useSystemProvidedLauncher = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
         if (preferredPackage == null || useSystemProvidedLauncher) {
-            // Using the component stored in config if no package name or forced.
-            final String secondaryHomeComponent = mContext.getResources().getString(
-                    com.android.internal.R.string.config_secondaryHomeComponent);
-            intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent));
+            // Using the package name stored in config if no preferred package name or forced.
+            final String secondaryHomePackage = mContext.getResources().getString(
+                    com.android.internal.R.string.config_secondaryHomePackage);
+            intent.setPackage(secondaryHomePackage);
         } else {
             intent.setPackage(preferredPackage);
         }
@@ -6136,13 +6153,6 @@
         }
 
         @Override
-        public void notifyDockedStackMinimizedChanged(boolean minimized) {
-            synchronized (mGlobalLock) {
-                mRootWindowContainer.setDockedStackMinimized(minimized);
-            }
-        }
-
-        @Override
         public int startActivitiesAsPackage(String packageName, @Nullable String featureId,
                 int userId, Intent[] intents, Bundle bOptions) {
             Objects.requireNonNull(intents, "intents");
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 8cf0881..4916c31 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -446,8 +446,6 @@
                         ? topOpeningAnim.getStatusBarTransitionsStartTime()
                         : SystemClock.uptimeMillis(),
                 AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
-        mDisplayContent.getDockedDividerController()
-                .notifyAppTransitionStarting(openingApps, transit);
 
         if (mRemoteAnimationController != null) {
             mRemoteAnimationController.goodToGo();
@@ -2308,14 +2306,14 @@
             }
             notifyAppTransitionTimeoutLocked();
             if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
-                    || !dc.mChangingApps.isEmpty()) {
+                    || !dc.mChangingContainers.isEmpty()) {
                 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                             "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b "
                                     + "mOpeningApps.size()=%d mClosingApps.size()=%d "
                                     + "mChangingApps.size()=%d",
                             dc.getDisplayId(), dc.mAppTransition.isTransitionSet(),
                             dc.mOpeningApps.size(), dc.mClosingApps.size(),
-                            dc.mChangingApps.size());
+                            dc.mChangingContainers.size());
 
                 setTimeout();
                 mService.mWindowPlacerLocked.performSurfacePlacement();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3f4e791..0912b2e 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -55,6 +55,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.NonNull;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -86,7 +87,7 @@
     private final WallpaperController mWallpaperControllerLocked;
     private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
 
-    private final ArrayMap<ActivityRecord, Integer> mTempTransitionReasons = new ArrayMap<>();
+    private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
 
     AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -104,7 +105,8 @@
     void handleAppTransitionReady() {
         mTempTransitionReasons.clear();
         if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
-                || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
+                || !transitionGoodToGo(mDisplayContent.mChangingContainers,
+                        mTempTransitionReasons)) {
             return;
         }
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
@@ -130,17 +132,21 @@
             // transition selection depends on wallpaper target visibility.
             mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
         }
-        appCount = mDisplayContent.mChangingApps.size();
+        appCount = mDisplayContent.mChangingContainers.size();
         for (int i = 0; i < appCount; ++i) {
             // Clearing for same reason as above.
-            mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
+            final ActivityRecord activity = getAppFromContainer(
+                    mDisplayContent.mChangingContainers.valueAtUnchecked(i));
+            if (activity != null) {
+                activity.clearAnimatingFlags();
+            }
         }
 
         // Adjust wallpaper before we pull the lower/upper target, since pending changes
         // (like the clearAnimatingFlags() above) might affect wallpaper target result.
         // Or, the opening app window should be a wallpaper target.
         mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
-                mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
+                mDisplayContent.mOpeningApps);
 
         // Determine if closing and opening app token sets are wallpaper targets, in which case
         // special animations are needed.
@@ -159,7 +165,7 @@
         // no need to do an animation. This is the case, for example, when this transition is being
         // done behind a dream window.
         final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
-                mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
+                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
         final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
         final ActivityRecord animLpActivity = allowAnimations
                 ? findAnimLayoutParamsToken(transit, activityTypes)
@@ -171,14 +177,13 @@
                 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
                 : null;
         final ActivityRecord topChangingApp = allowAnimations
-                ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
+                ? getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */)
                 : null;
         final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
         overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
 
         final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
-                || containsVoiceInteraction(mDisplayContent.mOpeningApps)
-                || containsVoiceInteraction(mDisplayContent.mChangingApps);
+                || containsVoiceInteraction(mDisplayContent.mOpeningApps);
 
         final int layoutRedo;
         mService.mSurfaceAnimationRunner.deferStartingAnimations();
@@ -206,7 +211,7 @@
 
         mDisplayContent.mOpeningApps.clear();
         mDisplayContent.mClosingApps.clear();
-        mDisplayContent.mChangingApps.clear();
+        mDisplayContent.mChangingContainers.clear();
         mDisplayContent.mUnknownAppVisibilityController.clear();
 
         // This has changed the visibility of windows, so perform
@@ -235,9 +240,9 @@
         return mainWindow != null ? mainWindow.mAttrs : null;
     }
 
-    RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity,
+    RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container,
             @TransitionType int transit, ArraySet<Integer> activityTypes) {
-        final RemoteAnimationDefinition definition = animLpActivity.getRemoteAnimationDefinition();
+        final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
         if (definition != null) {
             final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
             if (adapter != null) {
@@ -271,6 +276,11 @@
         }
     }
 
+    static ActivityRecord getAppFromContainer(WindowContainer wc) {
+        return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity()
+                : wc.asActivityRecord();
+    }
+
     /**
      * @return The window token that determines the animation theme.
      */
@@ -279,14 +289,14 @@
         ActivityRecord result;
         final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
         final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
-        final ArraySet<ActivityRecord> changingApps = mDisplayContent.mChangingApps;
+        final ArraySet<WindowContainer> changingApps = mDisplayContent.mChangingContainers;
 
         // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
         result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.getRemoteAnimationDefinition() != null
                         && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
         if (result != null) {
-            return result;
+            return getAppFromContainer(result);
         }
         result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.fillsParent() && w.findMainWindow() != null);
@@ -302,7 +312,7 @@
      *         of apps in {@code array1}, {@code array2}, and {@code array3}.
      */
     private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1,
-            ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3) {
+            ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3) {
         final ArraySet<Integer> result = new ArraySet<>();
         for (int i = array1.size() - 1; i >= 0; i--) {
             result.add(array1.valueAt(i).getActivityType());
@@ -317,7 +327,7 @@
     }
 
     private static ActivityRecord lookForHighestTokenWithFilter(ArraySet<ActivityRecord> array1,
-            ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3,
+            ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3,
             Predicate<ActivityRecord> filter) {
         final int array2base = array1.size();
         final int array3base = array2.size() + array2base;
@@ -325,15 +335,16 @@
         int bestPrefixOrderIndex = Integer.MIN_VALUE;
         ActivityRecord bestToken = null;
         for (int i = 0; i < count; i++) {
-            final ActivityRecord wtoken = i < array2base
+            final WindowContainer wtoken = i < array2base
                     ? array1.valueAt(i)
                     : (i < array3base
                             ? array2.valueAt(i - array2base)
                             : array3.valueAt(i - array3base));
             final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
-            if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
+            final ActivityRecord r = getAppFromContainer(wtoken);
+            if (r != null && filter.test(r) && prefixOrderIndex > bestPrefixOrderIndex) {
                 bestPrefixOrderIndex = prefixOrderIndex;
-                bestToken = wtoken;
+                bestToken = r;
             }
         }
         return bestToken;
@@ -589,21 +600,13 @@
     }
 
     private void handleChangingApps(@TransitionType int transit) {
-        final ArraySet<ActivityRecord> apps = mDisplayContent.mChangingApps;
+        final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers;
         final int appsCount = apps.size();
         for (int i = 0; i < appsCount; i++) {
-            ActivityRecord activity = apps.valueAt(i);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity);
-            activity.cancelAnimationOnly();
-            activity.applyAnimation(null, transit, true, false,
+            WindowContainer wc = apps.valueAt(i);
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc);
+            wc.applyAnimation(null, transit, true, false,
                     null /* animationFinishedCallback */);
-            activity.updateReportedVisibilityLocked();
-            mService.openSurfaceTransaction();
-            try {
-                activity.showAllWindowsLocked();
-            } finally {
-                mService.closeSurfaceTransaction("handleChangingApps");
-            }
         }
     }
 
@@ -628,8 +631,8 @@
         }
     }
 
-    private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps,
-            ArrayMap<ActivityRecord, Integer> outReasons) {
+    private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps,
+            ArrayMap<WindowContainer, Integer> outReasons) {
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
                 mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
@@ -652,13 +655,17 @@
                 return false;
             }
             for (int i = 0; i < apps.size(); i++) {
-                ActivityRecord activity = apps.valueAt(i);
+                WindowContainer wc = apps.valueAt(i);
+                final ActivityRecord activity = getAppFromContainer(wc);
+                if (activity == null) {
+                    continue;
+                }
                 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                                "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
-                                        + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
-                                activity, activity.allDrawn, activity.startingDisplayed,
-                                activity.startingMoved, activity.isRelaunching(),
-                                activity.startingWindow);
+                        "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+                                + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
+                        activity, activity.allDrawn, activity.startingDisplayed,
+                        activity.startingMoved, activity.isRelaunching(),
+                        activity.startingWindow);
 
 
                 final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
@@ -838,7 +845,7 @@
     @VisibleForTesting
     boolean isTransitWithinTask(@TransitionType int transit, Task task) {
         if (task == null
-                || !mDisplayContent.mChangingApps.isEmpty()) {
+                || !mDisplayContent.mChangingContainers.isEmpty()) {
             // if there is no task, then we can't constrain to the task.
             // if anything is changing, it can animate outside its task.
             return false;
@@ -882,12 +889,13 @@
      *                        {@link ActivityRecord#isVisible}.
      * @return The top {@link ActivityRecord}.
      */
-    private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) {
+    private ActivityRecord getTopApp(ArraySet<? extends WindowContainer> apps,
+            boolean ignoreInvisible) {
         int topPrefixOrderIndex = Integer.MIN_VALUE;
         ActivityRecord topApp = null;
         for (int i = apps.size() - 1; i >= 0; i--) {
-            final ActivityRecord app = apps.valueAt(i);
-            if (ignoreInvisible && !app.isVisible()) {
+            final ActivityRecord app = getAppFromContainer(apps.valueAt(i));
+            if (app == null || ignoreInvisible && !app.isVisible()) {
                 continue;
             }
             final int prefixOrderIndex = app.getPrefixOrderIndex();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e468810..5cd2930 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -91,11 +91,9 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.CHANGING_APPS;
 import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
-import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER;
 import static com.android.server.wm.DisplayContentProto.DPI;
 import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
 import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
@@ -132,7 +130,7 @@
 import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE;
 import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
 import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
-import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
+import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
 import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
@@ -314,7 +312,7 @@
 
     final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>();
     final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>();
-    final ArraySet<ActivityRecord> mChangingApps = new ArraySet<>();
+    final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>();
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
 
     private MetricsLogger mMetricsLogger;
@@ -1006,7 +1004,7 @@
             mDisplayPolicy.systemReady();
         }
         mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
-        mDividerControllerLocked = new DockedStackDividerController(mWmService, this);
+        mDividerControllerLocked = new DockedStackDividerController(this);
         mPinnedStackControllerLocked = new PinnedStackController(mWmService, this);
 
         final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
@@ -2233,12 +2231,6 @@
      * for bounds calculations.
      */
     void preOnConfigurationChanged() {
-        final DockedStackDividerController dividerController = getDockedDividerController();
-
-        if (dividerController != null) {
-            getDockedDividerController().onConfigurationChanged();
-        }
-
         final PinnedStackController pinnedStackController = getPinnedStackController();
 
         if (pinnedStackController != null) {
@@ -2622,10 +2614,11 @@
         // We also remove the outside touch area for resizing for all freeform
         // tasks (including the focused).
         // We save the focused task region once we find it, and add it back at the end.
-        // If the task is home stack and it is resizable in the minimized state, we want to
-        // exclude the docked stack from touch so we need the entire screen area and not just a
+        // If the task is home stack and it is resizable and visible (top of its root task), we want
+        // to exclude the docked stack from touch so we need the entire screen area and not just a
         // small portion which the home stack currently is resized to.
-        if (task.isActivityTypeHome() && task.getStack().isMinimizedDockAndHomeStackResizable()) {
+        if (task.isActivityTypeHome() && task.isVisible() && task.getStack().getTile() != null
+                && task.isResizeable()) {
             mDisplayContent.getBounds(mTmpRect);
         } else {
             task.getDimBounds(mTmpRect);
@@ -2634,6 +2627,8 @@
         if (task == focusedTask) {
             // Add the focused task rect back into the exclude region once we are done
             // processing stacks.
+            // NOTE: this *looks* like a no-op, but this usage of mTmpRect2 is expected by
+            //       updateTouchExcludeRegion.
             mTmpRect2.set(mTmpRect);
         }
 
@@ -2695,7 +2690,7 @@
             // Clear all transitions & screen frozen states when removing display.
             mOpeningApps.clear();
             mClosingApps.clear();
-            mChangingApps.clear();
+            mChangingContainers.clear();
             mUnknownAppVisibilityController.clear();
             mAppTransition.removeAppTransitionTimeoutCallbacks();
             handleAnimatingStoppedAndTransition();
@@ -2747,58 +2742,6 @@
         return mDeferredRemoval;
     }
 
-    boolean animateForIme(float interpolatedValue, float animationTarget,
-            float dividerAnimationTarget) {
-        boolean updated = false;
-
-        for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = mTaskContainers.getChildAt(i);
-            if (stack == null || !stack.isAdjustedForIme()) {
-                continue;
-            }
-
-            if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) {
-                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
-                updated = true;
-            } else {
-                mDividerControllerLocked.mLastAnimationProgress =
-                        mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue);
-                mDividerControllerLocked.mLastDividerProgress =
-                        mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue);
-                updated |= stack.updateAdjustForIme(
-                        mDividerControllerLocked.mLastAnimationProgress,
-                        mDividerControllerLocked.mLastDividerProgress,
-                        false /* force */);
-            }
-            if (interpolatedValue >= 1f) {
-                stack.endImeAdjustAnimation();
-            }
-        }
-
-        return updated;
-    }
-
-    boolean clearImeAdjustAnimation() {
-        boolean changed = false;
-        for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = mTaskContainers.getChildAt(i);
-            if (stack != null && stack.isAdjustedForIme()) {
-                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
-                changed  = true;
-            }
-        }
-        return changed;
-    }
-
-    void beginImeAdjustAnimation() {
-        for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = mTaskContainers.getChildAt(i);
-            if (stack.isVisible() && stack.isAdjustedForIme()) {
-                stack.beginImeAdjustAnimation();
-            }
-        }
-    }
-
     void adjustForImeIfNeeded() {
         final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
@@ -2893,7 +2836,6 @@
             final ActivityStack stack = mTaskContainers.getChildAt(i);
             stack.dumpDebug(proto, TASKS, logLevel);
         }
-        mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
         for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) {
             final WindowToken windowToken = mOverlayContainers.getChildAt(i);
             windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel);
@@ -2916,9 +2858,6 @@
         for (int i = mClosingApps.size() - 1; i >= 0; i--) {
             mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS);
         }
-        for (int i = mChangingApps.size() - 1; i >= 0; i--) {
-            mChangingApps.valueAt(i).writeIdentifierToProto(proto, CHANGING_APPS);
-        }
 
         proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
         final ActivityStack focusedStack = getFocusedStack();
@@ -3066,8 +3005,6 @@
         }
 
         pw.println();
-        mDividerControllerLocked.dump(prefix, pw);
-        pw.println();
         mPinnedStackControllerLocked.dump(prefix, pw);
 
         pw.println();
@@ -3670,7 +3607,7 @@
             }
         }
 
-        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingApps.isEmpty()) {
+        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingContainers.isEmpty()) {
             pw.println();
             if (mOpeningApps.size() > 0) {
                 pw.print("  mOpeningApps="); pw.println(mOpeningApps);
@@ -3678,8 +3615,8 @@
             if (mClosingApps.size() > 0) {
                 pw.print("  mClosingApps="); pw.println(mClosingApps);
             }
-            if (mChangingApps.size() > 0) {
-                pw.print("  mChangingApps="); pw.println(mChangingApps);
+            if (mChangingContainers.size() > 0) {
+                pw.print("  mChangingApps="); pw.println(mChangingContainers);
             }
         }
 
@@ -4088,7 +4025,7 @@
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
 
-        mWmService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
+        mWmService.mH.sendEmptyMessage(UPDATE_MULTI_WINDOW_STACKS);
     }
 
     /**
@@ -4696,17 +4633,18 @@
         @Override
         int getOrientation(int candidate) {
             if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
-                // Apps and their containers are not allowed to specify an orientation while the
-                // docked stack is visible...except for the home stack if the docked stack is
-                // minimized and it actually set something and the bounds is different from  the
-                // display.
+                // Apps and their containers are not allowed to specify an orientation while using
+                // root tasks...except for the home stack if it is not resizable and currently
+                // visible (top of) its root task.
                 if (mRootHomeTask != null && mRootHomeTask.isVisible()
-                        && mDividerControllerLocked.isMinimizedDock()
-                        && !(mDividerControllerLocked.isHomeStackResizable()
-                        && mRootHomeTask.matchParentBounds())) {
-                    final int orientation = mRootHomeTask.getOrientation();
-                    if (orientation != SCREEN_ORIENTATION_UNSET) {
-                        return orientation;
+                        && mRootHomeTask.getTile() != null) {
+                    final Task topMost = mRootHomeTask.getTopMostTask();
+                    final boolean resizable = topMost == null && topMost.isResizeable();
+                    if (!(resizable && mRootHomeTask.matchParentBounds())) {
+                        final int orientation = mRootHomeTask.getOrientation();
+                        if (orientation != SCREEN_ORIENTATION_UNSET) {
+                            return orientation;
+                        }
                     }
                 }
                 return SCREEN_ORIENTATION_UNSPECIFIED;
@@ -6171,8 +6109,6 @@
                     t.removeAllChildren();
                 }
             }
-            mDividerControllerLocked.setMinimizedDockedStack(false /* minimized */,
-                    false /* animate */);
         } finally {
             final ActivityStack topFullscreenStack =
                     getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f02a9dd..497c473 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1178,8 +1178,6 @@
                     return R.anim.dock_left_enter;
                 }
             }
-        } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
-            return selectDockedDividerAnimation(win, transit);
         }
 
         if (transit == TRANSIT_PREVIEW_DONE) {
@@ -1204,36 +1202,6 @@
         return ANIMATION_STYLEABLE;
     }
 
-    private int selectDockedDividerAnimation(WindowState win, int transit) {
-        int insets = mDisplayContent.getDockedDividerController().getContentInsets();
-
-        // If the divider is behind the navigation bar, don't animate.
-        final Rect frame = win.getFrameLw();
-        final boolean behindNavBar = mNavigationBar != null
-                && ((mNavigationBarPosition == NAV_BAR_BOTTOM
-                && frame.top + insets >= mNavigationBar.getFrameLw().top)
-                || (mNavigationBarPosition == NAV_BAR_RIGHT
-                && frame.left + insets >= mNavigationBar.getFrameLw().left)
-                || (mNavigationBarPosition == NAV_BAR_LEFT
-                && frame.right - insets <= mNavigationBar.getFrameLw().right));
-        final boolean landscape = frame.height() > frame.width();
-        final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
-                || frame.left + insets >= win.getDisplayFrameLw().right);
-        final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
-                || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
-        final boolean offscreen = offscreenLandscape || offscreenPortrait;
-        if (behindNavBar || offscreen) {
-            return ANIMATION_STYLEABLE;
-        }
-        if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
-            return R.anim.fade_in;
-        } else if (transit == TRANSIT_EXIT) {
-            return R.anim.fade_out;
-        } else {
-            return ANIMATION_STYLEABLE;
-        }
-    }
-
     /**
      * Called when a new system UI visibility is being reported, allowing
      * the policy to adjust what is actually reported.
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 958c8ae..20738ed 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -16,330 +16,26 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
-
-import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
-import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.DisplayCutout;
-import android.view.DisplayInfo;
-import android.view.IDockedStackListener;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.inputmethod.SoftInputShowHideReason;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.server.LocalServices;
-import com.android.server.inputmethod.InputMethodManagerInternal;
-import com.android.server.wm.WindowManagerService.H;
-
-import java.io.PrintWriter;
 
 /**
  * Keeps information about the docked stack divider.
  */
 public class DockedStackDividerController {
 
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
-
-    /**
-     * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
-     * revealing surface at the earliest.
-     */
-    private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
-
-    /**
-     * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
-     * revealing surface at the latest.
-     */
-    private static final float CLIP_REVEAL_MEET_LAST = 1f;
-
-    /**
-     * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
-     * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
-     */
-    private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
-
-    /**
-     * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
-     * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
-     */
-    private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
-
-    private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
-            new PathInterpolator(0.2f, 0f, 0.1f, 1f);
-
-    private static final long IME_ADJUST_ANIM_DURATION = 280;
-
-    private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
-
-    private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
-
-    private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
-    private int mDividerWindowWidth;
-    private int mDividerWindowWidthInactive;
-    private int mDividerInsets;
-    private int mTaskHeightInMinimizedMode;
     private boolean mResizing;
-    private WindowState mWindow;
-    private final Rect mTmpRect = new Rect();
-    private final Rect mTmpRect2 = new Rect();
-    private final Rect mTmpRect3 = new Rect();
-    private final Rect mLastRect = new Rect();
-    private boolean mLastVisibility = false;
-    private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
-            = new RemoteCallbackList<>();
 
-    private boolean mMinimizedDock;
-    private int mOriginalDockedSide = DOCKED_INVALID;
-    private boolean mAnimatingForMinimizedDockedStack;
-    private boolean mAnimationStarted;
-    private long mAnimationStartTime;
-    private float mAnimationStart;
-    private float mAnimationTarget;
-    private long mAnimationDuration;
-    private boolean mAnimationStartDelayed;
-    private final Interpolator mMinimizedDockInterpolator;
-    private float mMaximizeMeetFraction;
     private final Rect mTouchRegion = new Rect();
-    private boolean mAnimatingForIme;
-    private boolean mAdjustedForIme;
-    private int mImeHeight;
-    private WindowState mDelayedImeWin;
-    private boolean mAdjustedForDivider;
-    private float mDividerAnimationStart;
-    private float mDividerAnimationTarget;
-    float mLastAnimationProgress;
-    float mLastDividerProgress;
-    private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
-    private boolean mImeHideRequested;
-    private ActivityStack mDimmedStack;
 
-    DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
-        mService = service;
+    DockedStackDividerController(DisplayContent displayContent) {
         mDisplayContent = displayContent;
-        final Context context = service.mContext;
-        mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
-                context, android.R.interpolator.fast_out_slow_in);
-        loadDimens();
-    }
-
-    int getSmallestWidthDpForBounds(Rect bounds) {
-        final DisplayInfo di = mDisplayContent.getDisplayInfo();
-
-        final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
-        final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
-        int minWidth = Integer.MAX_VALUE;
-
-        // Go through all screen orientations and find the orientation in which the task has the
-        // smallest width.
-        for (int rotation = 0; rotation < 4; rotation++) {
-            mTmpRect.set(bounds);
-            mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect);
-            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
-            mTmpRect2.set(0, 0,
-                    rotated ? baseDisplayHeight : baseDisplayWidth,
-                    rotated ? baseDisplayWidth : baseDisplayHeight);
-            final int orientation = mTmpRect2.width() <= mTmpRect2.height()
-                    ? ORIENTATION_PORTRAIT
-                    : ORIENTATION_LANDSCAPE;
-            final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation);
-            final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
-                    getContentWidth());
-
-            final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(
-                    rotation).getDisplayCutout();
-
-            // Since we only care about feasible states, snap to the closest snap target, like it
-            // would happen when actually rotating the screen.
-            final int snappedPosition = mSnapAlgorithmForRotation[rotation]
-                    .calculateNonDismissingSnapTarget(position).position;
-            DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
-                    mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
-            mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, mTmpRect2.width(),
-                    mTmpRect2.height(), displayCutout, mTmpRect3);
-            mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
-            minWidth = Math.min(mTmpRect.width(), minWidth);
-        }
-        return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
-    }
-
-    /**
-     * Get the current docked side. Determined by its location of {@param bounds} within
-     * {@param displayRect} but if both are the same, it will try to dock to each side and determine
-     * if allowed in its respected {@param orientation}.
-     *
-     * @param bounds bounds of the docked task to get which side is docked
-     * @param displayRect bounds of the display that contains the docked task
-     * @param orientation the origination of device
-     * @return current docked side
-     */
-    int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) {
-        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-            // Portrait mode, docked either at the top or the bottom.
-            final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
-            if (diff > 0) {
-                return DOCKED_TOP;
-            } else if (diff < 0) {
-                return DOCKED_BOTTOM;
-            }
-            return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation)
-                    ? DOCKED_TOP : DOCKED_BOTTOM;
-        } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            // Landscape mode, docked either on the left or on the right.
-            final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
-            if (diff > 0) {
-                return DOCKED_LEFT;
-            } else if (diff < 0) {
-                return DOCKED_RIGHT;
-            }
-            return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation)
-                    ? DOCKED_LEFT : DOCKED_RIGHT;
-        }
-        return DOCKED_INVALID;
-    }
-
-    void getHomeStackBoundsInDockedMode(Configuration parentConfig, int dockSide, Rect outBounds) {
-        final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
-        final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
-        final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
-        mDisplayContent.getDisplayPolicy().getStableInsetsLw(
-                parentConfig.windowConfiguration.getRotation(), displayWidth, displayHeight,
-                displayCutout, mTmpRect);
-        int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
-        // The offset in the left (landscape)/top (portrait) is calculated with the minimized
-        // offset value with the divider size and any system insets in that direction.
-        if (parentConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
-            outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
-                    displayWidth, displayHeight);
-        } else {
-            // In landscape also inset the left/right side with the status bar height to match the
-            // minimized size height in portrait mode.
-            final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
-            int left = mTmpRect.left;
-            int right = displayWidth - mTmpRect.right;
-            if (dockSide == DOCKED_LEFT) {
-                left += primaryTaskWidth;
-            } else if (dockSide == DOCKED_RIGHT) {
-                right -= primaryTaskWidth;
-            }
-            outBounds.set(left, 0, right, displayHeight);
-        }
-    }
-
-    boolean isHomeStackResizable() {
-        final ActivityStack homeStack = mDisplayContent.getRootHomeTask();
-        if (homeStack == null) {
-            return false;
-        }
-        final Task homeTask = homeStack.getTopMostTask();
-        return homeTask != null && homeTask.isResizeable();
-    }
-
-    private void initSnapAlgorithmForRotations() {
-        final Configuration baseConfig = mDisplayContent.getConfiguration();
-
-        // Initialize the snap algorithms for all 4 screen orientations.
-        final Configuration config = new Configuration();
-        for (int rotation = 0; rotation < 4; rotation++) {
-            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
-            final int dw = rotated
-                    ? mDisplayContent.mBaseDisplayHeight
-                    : mDisplayContent.mBaseDisplayWidth;
-            final int dh = rotated
-                    ? mDisplayContent.mBaseDisplayWidth
-                    : mDisplayContent.mBaseDisplayHeight;
-            final DisplayCutout displayCutout =
-                    mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
-            final DisplayPolicy displayPolicy =  mDisplayContent.getDisplayPolicy();
-            displayPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
-            config.unset();
-            config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
-
-            final int appWidth = displayPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
-                    baseConfig.uiMode, displayCutout);
-            final int appHeight = displayPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
-                    baseConfig.uiMode, displayCutout);
-            displayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
-            final int leftInset = mTmpRect.left;
-            final int topInset = mTmpRect.top;
-
-            config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/,
-                    leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
-
-            final float density = mDisplayContent.getDisplayMetrics().density;
-            config.screenWidthDp = (int) (displayPolicy.getConfigDisplayWidth(dw, dh, rotation,
-                    baseConfig.uiMode, displayCutout) / density);
-            config.screenHeightDp = (int) (displayPolicy.getConfigDisplayHeight(dw, dh, rotation,
-                    baseConfig.uiMode, displayCutout) / density);
-            final Context rotationContext = mService.mContext.createConfigurationContext(config);
-            mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
-                    rotationContext.getResources(), dw, dh, getContentWidth(),
-                    config.orientation == ORIENTATION_PORTRAIT, mTmpRect);
-        }
-    }
-
-    private void loadDimens() {
-        final Context context = mService.mContext;
-        mDividerWindowWidth = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_divider_thickness);
-        mDividerInsets = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_divider_insets);
-        mDividerWindowWidthInactive = WindowManagerService.dipToPixel(
-                DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics());
-        mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.task_height_of_minimized_mode);
-        initSnapAlgorithmForRotations();
-    }
-
-    void onConfigurationChanged() {
-        loadDimens();
     }
 
     boolean isResizing() {
         return mResizing;
     }
 
-    int getContentWidth() {
-        return mDividerWindowWidth - 2 * mDividerInsets;
-    }
-
-    int getContentInsets() {
-        return mDividerInsets;
-    }
-
-    int getContentWidthInactive() {
-        return mDividerWindowWidthInactive;
-    }
-
     void setResizing(boolean resizing) {
         if (mResizing != resizing) {
             mResizing = resizing;
@@ -353,676 +49,10 @@
 
     void getTouchRegion(Rect outRegion) {
         outRegion.set(mTouchRegion);
-        if (mWindow != null) {
-            outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top);
-        }
     }
 
     private void resetDragResizingChangeReported() {
         mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
                 true /* traverseTopToBottom */ );
     }
-
-    void setWindow(WindowState window) {
-        mWindow = window;
-        reevaluateVisibility(false);
-    }
-
-    void reevaluateVisibility(boolean force) {
-        if (mWindow == null) {
-            return;
-        }
-        ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask();
-
-        // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
-        final boolean visible = stack != null;
-        if (mLastVisibility == visible && !force) {
-            return;
-        }
-        mLastVisibility = visible;
-        notifyDockedDividerVisibilityChanged(visible);
-        if (!visible) {
-            setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f);
-        }
-    }
-
-    private boolean wasVisible() {
-        return mLastVisibility;
-    }
-
-    void setAdjustedForIme(
-            boolean adjustedForIme, boolean adjustedForDivider,
-            boolean animate, WindowState imeWin, int imeHeight) {
-        if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
-                || mAdjustedForDivider != adjustedForDivider) {
-            if (animate && !mAnimatingForMinimizedDockedStack) {
-                // Notify SystemUI to set the target docked stack size according current docked
-                // state without animation when calling startImeAdjustAnimation.
-                notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
-                        isHomeStackResizable());
-                startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
-            } else {
-                // Animation might be delayed, so only notify if we don't run an animation.
-                notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
-            }
-            mAdjustedForIme = adjustedForIme;
-            mImeHeight = imeHeight;
-            mAdjustedForDivider = adjustedForDivider;
-        }
-    }
-
-    int getImeHeightAdjustedFor() {
-        return mImeHeight;
-    }
-
-    void positionDockedStackedDivider(Rect frame) {
-        ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask();
-        if (stack == null) {
-            // Unfortunately we might end up with still having a divider, even though the underlying
-            // stack was already removed. This is because we are on AM thread and the removal of the
-            // divider was deferred to WM thread and hasn't happened yet. In that case let's just
-            // keep putting it in the same place it was before the stack was removed to have
-            // continuity and prevent it from jumping to the center. It will get hidden soon.
-            frame.set(mLastRect);
-            return;
-        } else {
-            stack.getDimBounds(mTmpRect);
-        }
-        int side = stack.getDockSide();
-        switch (side) {
-            case DOCKED_LEFT:
-                frame.set(mTmpRect.right - mDividerInsets, frame.top,
-                        mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
-                break;
-            case DOCKED_TOP:
-                frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
-                        mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
-                break;
-            case DOCKED_RIGHT:
-                frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
-                        mTmpRect.left + mDividerInsets, frame.bottom);
-                break;
-            case DOCKED_BOTTOM:
-                frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
-                        frame.right, mTmpRect.top + mDividerInsets);
-                break;
-        }
-        mLastRect.set(frame);
-    }
-
-    private void notifyDockedDividerVisibilityChanged(boolean visible) {
-        final int size = mDockedStackListeners.beginBroadcast();
-        for (int i = 0; i < size; ++i) {
-            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
-            try {
-                listener.onDividerVisibilityChanged(visible);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
-            }
-        }
-        mDockedStackListeners.finishBroadcast();
-    }
-
-    /**
-     * Checks if the primary stack is allowed to dock to a specific side based on its original dock
-     * side.
-     *
-     * @param dockSide the side to see if it is valid
-     * @return true if the side provided is valid
-     */
-    boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
-        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
-        return isDockSideAllowed(dockSide, mOriginalDockedSide,
-                policy.navigationBarPosition(parentRect.width(), parentRect.height(), rotation),
-                policy.navigationBarCanMove());
-    }
-
-    @VisibleForTesting
-    static boolean isDockSideAllowed(int dockSide, int originalDockSide, int navBarPosition,
-            boolean navigationBarCanMove) {
-        if (dockSide == DOCKED_TOP) {
-            return true;
-        }
-
-        if (navigationBarCanMove) {
-            // Only allow the dockside opposite to the nav bar position in landscape
-            return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
-                    || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
-        }
-
-        // Side is the same as original side
-        if (dockSide == originalDockSide) {
-            return true;
-        }
-
-        // Only if original docked side was top in portrait will allow left for landscape
-        return dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP;
-    }
-
-    void notifyDockedStackExistsChanged(boolean exists) {
-        // TODO(multi-display): Perform all actions only for current display.
-        final int size = mDockedStackListeners.beginBroadcast();
-        for (int i = 0; i < size; ++i) {
-            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
-            try {
-                listener.onDockedStackExistsChanged(exists);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
-            }
-        }
-        mDockedStackListeners.finishBroadcast();
-        if (exists) {
-            InputMethodManagerInternal inputMethodManagerInternal =
-                    LocalServices.getService(InputMethodManagerInternal.class);
-            if (inputMethodManagerInternal != null) {
-
-                // Hide the current IME to avoid problems with animations from IME adjustment when
-                // attaching the docked stack.
-                inputMethodManagerInternal.hideCurrentInputMethod(
-                        SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED);
-                mImeHideRequested = true;
-            }
-
-            // If a primary stack was just created, it will not have access to display content at
-            // this point so pass it from here to get a valid dock side.
-            final ActivityStack stack =
-                    mDisplayContent.getRootSplitScreenPrimaryTask();
-            mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent);
-            return;
-        }
-        mOriginalDockedSide = DOCKED_INVALID;
-        setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
-
-        if (mDimmedStack != null) {
-            mDimmedStack.stopDimming();
-            mDimmedStack = null;
-        }
-    }
-
-    /**
-     * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}.
-     */
-    void resetImeHideRequested() {
-        mImeHideRequested = false;
-    }
-
-    /**
-     * The docked stack divider controller makes sure the IME gets hidden when attaching the docked
-     * stack, to avoid animation problems. This flag indicates whether the request to hide the IME
-     * has been sent in an asynchronous manner, and the IME should be treated as hidden already.
-     *
-     * @return whether IME hide request has been sent
-     */
-    boolean isImeHideRequested() {
-        return mImeHideRequested;
-    }
-
-    private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate,
-            boolean isHomeStackResizable) {
-        long animDuration = 0;
-        if (animate) {
-            final ActivityStack stack =
-                    mDisplayContent.getRootSplitScreenPrimaryTask();
-            final long transitionDuration = isAnimationMaximizing()
-                    ? mDisplayContent.mAppTransition.getLastClipRevealTransitionDuration()
-                    : DEFAULT_APP_TRANSITION_DURATION;
-            mAnimationDuration = (long)
-                    (transitionDuration * mService.getTransitionAnimationScaleLocked());
-            mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
-            animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
-        }
-        final int size = mDockedStackListeners.beginBroadcast();
-        for (int i = 0; i < size; ++i) {
-            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
-            try {
-                listener.onDockedStackMinimizedChanged(minimizedDock, animDuration,
-                        isHomeStackResizable);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
-            }
-        }
-        mDockedStackListeners.finishBroadcast();
-        // Only notify ATM after we update the remote listeners, otherwise it may trigger another
-        // minimize change, which would lead to an inversion of states send to the listeners
-        mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
-    }
-
-    void notifyDockSideChanged(int newDockSide) {
-        final int size = mDockedStackListeners.beginBroadcast();
-        for (int i = 0; i < size; ++i) {
-            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
-            try {
-                listener.onDockSideChanged(newDockSide);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
-            }
-        }
-        mDockedStackListeners.finishBroadcast();
-    }
-
-    private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
-        final int size = mDockedStackListeners.beginBroadcast();
-        for (int i = 0; i < size; ++i) {
-            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
-            try {
-                listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
-            } catch (RemoteException e) {
-                Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
-            }
-        }
-        mDockedStackListeners.finishBroadcast();
-    }
-
-    void registerDockedStackListener(IDockedStackListener listener) {
-        mDockedStackListeners.register(listener);
-        notifyDockedDividerVisibilityChanged(wasVisible());
-        notifyDockedStackExistsChanged(
-                mDisplayContent.getRootSplitScreenPrimaryTask() != null);
-        notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
-                isHomeStackResizable());
-        notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
-
-    }
-
-    /**
-     * Shows a dim layer with {@param alpha} if {@param visible} is true and
-     * {@param targetWindowingMode} isn't
-     * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the
-     * display in that windowing mode.
-     */
-    void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
-        // TODO: Maybe only allow split-screen windowing modes?
-        final ActivityStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
-                ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
-                : null;
-        final ActivityStack dockedStack = mDisplayContent.getRootSplitScreenPrimaryTask();
-        boolean visibleAndValid = visible && stack != null && dockedStack != null;
-
-        // Ensure an old dim that was shown for the docked stack divider is removed so we don't end
-        // up with dim layers that can no longer be removed.
-        if (mDimmedStack != null && mDimmedStack != stack) {
-            mDimmedStack.stopDimming();
-            mDimmedStack = null;
-        }
-
-        if (visibleAndValid) {
-            mDimmedStack = stack;
-            stack.dim(alpha);
-        }
-        if (!visibleAndValid && stack != null) {
-            mDimmedStack = null;
-            stack.stopDimming();
-        }
-    }
-
-    /**
-     * Notifies the docked stack divider controller of a visibility change that happens without
-     * an animation.
-     */
-    void notifyAppVisibilityChanged() {
-        checkMinimizeChanged(false /* animate */);
-    }
-
-    void notifyAppTransitionStarting(ArraySet<ActivityRecord> openingApps, int appTransition) {
-        final boolean wasMinimized = mMinimizedDock;
-        checkMinimizeChanged(true /* animate */);
-
-        // We were minimized, and now we are still minimized, but somebody is trying to launch an
-        // app in docked stack, better show recent apps so we actually get unminimized! However do
-        // not do this if keyguard is dismissed such as when the device is unlocking. This catches
-        // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
-        // we couldn't retrace the launch of the app in the docked stack to the launch from
-        // homescreen.
-        if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
-                && appTransition != TRANSIT_NONE &&
-                !AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
-            if (mService.mAtmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) {
-                // When the home activity is the recents component and we are already minimized,
-                // then there is nothing to do here since home is already visible
-            } else {
-                mService.showRecentApps();
-            }
-        }
-    }
-
-    /**
-     * @return true if {@param apps} contains an activity in the docked stack, false otherwise.
-     */
-    private boolean containsAppInDockedStack(ArraySet<ActivityRecord> apps) {
-        for (int i = apps.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = apps.valueAt(i);
-            if (activity.getTask() != null && activity.inSplitScreenPrimaryWindowingMode()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    boolean isMinimizedDock() {
-        return mMinimizedDock;
-    }
-
-    void checkMinimizeChanged(boolean animate) {
-        if (mDisplayContent.getRootSplitScreenPrimaryTask() == null) {
-            return;
-        }
-        final ActivityStack homeStack = mDisplayContent.getRootHomeTask();
-        if (homeStack == null) {
-            return;
-        }
-        final Task homeTask = homeStack.getTopMostTask();
-        if (homeTask == null || !isWithinDisplay(homeTask)) {
-            return;
-        }
-
-        // Do not minimize when dock is already minimized while keyguard is showing and not
-        // occluded such as unlocking the screen
-        if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
-            return;
-        }
-        final ActivityStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
-                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
-        final boolean minimizedForRecentsAnimation = recentsAnim != null &&
-                recentsAnim.isSplitScreenMinimized();
-        boolean homeVisible = homeTask.getTopVisibleActivity() != null;
-        if (homeVisible && topSecondaryStack != null) {
-            // Home should only be considered visible if it is greater or equal to the top secondary
-            // stack in terms of z-order.
-            homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
-        }
-        setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate);
-    }
-
-    private boolean isWithinDisplay(Task task) {
-        task.getBounds(mTmpRect);
-        mDisplayContent.getBounds(mTmpRect2);
-        return mTmpRect.intersect(mTmpRect2);
-    }
-
-    /**
-     * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
-     * docked stack are heavily clipped so you can only see a minimal peek state.
-     *
-     * @param minimizedDock Whether the docked stack is currently minimized.
-     * @param animate Whether to animate the change.
-     */
-    void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
-        final boolean wasMinimized = mMinimizedDock;
-        mMinimizedDock = minimizedDock;
-        if (minimizedDock == wasMinimized) {
-            return;
-        }
-
-        final boolean imeChanged = clearImeAdjustAnimation();
-        boolean minimizedChange = false;
-        if (isHomeStackResizable()) {
-            notifyDockedStackMinimizedChanged(minimizedDock, animate,
-                    true /* isHomeStackResizable */);
-            minimizedChange = true;
-        } else {
-            if (minimizedDock) {
-                if (animate) {
-                    startAdjustAnimation(0f, 1f);
-                } else {
-                    minimizedChange |= setMinimizedDockedStack(true);
-                }
-            } else {
-                if (animate) {
-                    startAdjustAnimation(1f, 0f);
-                } else {
-                    minimizedChange |= setMinimizedDockedStack(false);
-                }
-            }
-        }
-        if (imeChanged || minimizedChange) {
-            if (imeChanged && !minimizedChange) {
-                Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing,"
-                        + " minimizedDock=" + minimizedDock
-                        + " minimizedChange=" + minimizedChange);
-            }
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
-    private boolean clearImeAdjustAnimation() {
-        final boolean changed = mDisplayContent.clearImeAdjustAnimation();
-        mAnimatingForIme = false;
-        return changed;
-    }
-
-    private void startAdjustAnimation(float from, float to) {
-        mAnimatingForMinimizedDockedStack = true;
-        mAnimationStarted = false;
-        mAnimationStart = from;
-        mAnimationTarget = to;
-    }
-
-    private void startImeAdjustAnimation(
-            boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
-
-        // If we're not in an animation, the starting point depends on whether we're adjusted
-        // or not. If we're already in an animation, we start from where the current animation
-        // left off, so that the motion doesn't look discontinuous.
-        if (!mAnimatingForIme) {
-            mAnimationStart = mAdjustedForIme ? 1 : 0;
-            mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
-            mLastAnimationProgress = mAnimationStart;
-            mLastDividerProgress = mDividerAnimationStart;
-        } else {
-            mAnimationStart = mLastAnimationProgress;
-            mDividerAnimationStart = mLastDividerProgress;
-        }
-        mAnimatingForIme = true;
-        mAnimationStarted = false;
-        mAnimationTarget = adjustedForIme ? 1 : 0;
-        mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
-
-        mDisplayContent.beginImeAdjustAnimation();
-
-        // We put all tasks into drag resizing mode - wait until all of them have completed the
-        // drag resizing switch.
-        final Runnable existingWaitingForDrwanCallback =
-                mService.mWaitingForDrawnCallbacks.get(mService.mRoot);
-        if (existingWaitingForDrwanCallback != null) {
-            mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, mService.mRoot);
-            mService.mH.sendMessageDelayed(mService.mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT,
-                    mService.mRoot),
-                    IME_ADJUST_DRAWN_TIMEOUT);
-            mAnimationStartDelayed = true;
-            if (imeWin != null) {
-
-                // There might be an old window delaying the animation start - clear it.
-                if (mDelayedImeWin != null) {
-                    mDelayedImeWin.endDelayingAnimationStart();
-                }
-                mDelayedImeWin = imeWin;
-                imeWin.startDelayingAnimationStart();
-            }
-
-            // If we are already waiting for something to be drawn, clear out the old one so it
-            // still gets executed.
-            // TODO: Have a real system where we can wait on different windows to be drawn with
-            // different callbacks.
-            existingWaitingForDrwanCallback.run();
-            mService.mWaitingForDrawnCallbacks.put(mService.mRoot, () -> {
-                synchronized (mService.mGlobalLock) {
-                    mAnimationStartDelayed = false;
-                    if (mDelayedImeWin != null) {
-                        mDelayedImeWin.endDelayingAnimationStart();
-                    }
-                    // If the adjust status changed since this was posted, only notify
-                    // the new states and don't animate.
-                    long duration = 0;
-                    if (mAdjustedForIme == adjustedForIme
-                            && mAdjustedForDivider == adjustedForDivider) {
-                        duration = IME_ADJUST_ANIM_DURATION;
-                    } else {
-                        Slog.w(TAG, "IME adjust changed while waiting for drawn:"
-                                + " adjustedForIme=" + adjustedForIme
-                                + " adjustedForDivider=" + adjustedForDivider
-                                + " mAdjustedForIme=" + mAdjustedForIme
-                                + " mAdjustedForDivider=" + mAdjustedForDivider);
-                    }
-                    notifyAdjustedForImeChanged(
-                            mAdjustedForIme || mAdjustedForDivider, duration);
-                }
-            });
-        } else {
-            notifyAdjustedForImeChanged(
-                    adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
-        }
-    }
-
-    private boolean setMinimizedDockedStack(boolean minimized) {
-        final ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask();
-        notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
-        return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
-    }
-
-    private boolean isAnimationMaximizing() {
-        return mAnimationTarget == 0f;
-    }
-
-    public boolean animate(long now) {
-        if (mWindow == null) {
-            return false;
-        }
-        if (mAnimatingForMinimizedDockedStack) {
-            return animateForMinimizedDockedStack(now);
-        } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
-            // To prevent task stack resize animation may flicking when playing app transition
-            // animation & IME window enter animation in parallel, make sure app transition is done
-            // and then start to animate for IME.
-            return animateForIme(now);
-        }
-        return false;
-    }
-
-    private boolean animateForIme(long now) {
-        if (!mAnimationStarted || mAnimationStartDelayed) {
-            mAnimationStarted = true;
-            mAnimationStartTime = now;
-            mAnimationDuration = (long)
-                    (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
-        }
-        float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
-        t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
-                .getInterpolation(t);
-        final boolean updated =
-                mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget);
-        if (updated) {
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-        if (t >= 1.0f) {
-            mLastAnimationProgress = mAnimationTarget;
-            mLastDividerProgress = mDividerAnimationTarget;
-            mAnimatingForIme = false;
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    private boolean animateForMinimizedDockedStack(long now) {
-        final ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask();
-        if (!mAnimationStarted) {
-            mAnimationStarted = true;
-            mAnimationStartTime = now;
-            notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */,
-                    isHomeStackResizable() /* isHomeStackResizable */);
-        }
-        float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
-        t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
-                .getInterpolation(t);
-        if (stack != null) {
-            if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
-                mService.mWindowPlacerLocked.performSurfacePlacement();
-            }
-        }
-        if (t >= 1.0f) {
-            mAnimatingForMinimizedDockedStack = false;
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    float getInterpolatedAnimationValue(float t) {
-        return t * mAnimationTarget + (1 - t) * mAnimationStart;
-    }
-
-    float getInterpolatedDividerValue(float t) {
-        return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
-    }
-
-    /**
-     * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
-     */
-    private float getMinimizeAmount(ActivityStack stack, float t) {
-        final float naturalAmount = getInterpolatedAnimationValue(t);
-        if (isAnimationMaximizing()) {
-            return adjustMaximizeAmount(stack, t, naturalAmount);
-        } else {
-            return naturalAmount;
-        }
-    }
-
-    /**
-     * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
-     * during the transition such that the edge of the clip reveal rect is met earlier in the
-     * transition so we don't create a visible "hole", but only if both the clip reveal and the
-     * docked stack divider start from about the same portion on the screen.
-     */
-    private float adjustMaximizeAmount(ActivityStack stack, float t, float naturalAmount) {
-        if (mMaximizeMeetFraction == 1f) {
-            return naturalAmount;
-        }
-        final int minimizeDistance = stack.getMinimizeDistance();
-        final float startPrime = mDisplayContent.mAppTransition.getLastClipRevealMaxTranslation()
-                / (float) minimizeDistance;
-        final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
-        final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
-        return amountPrime * t2 + naturalAmount * (1 - t2);
-    }
-
-    /**
-     * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
-     * edge. See {@link #adjustMaximizeAmount}.
-     */
-    private float getClipRevealMeetFraction(ActivityStack stack) {
-        if (!isAnimationMaximizing() || stack == null ||
-                !mDisplayContent.mAppTransition.hadClipRevealAnimation()) {
-            return 1f;
-        }
-        final int minimizeDistance = stack.getMinimizeDistance();
-        final float fraction = Math.abs(mDisplayContent.mAppTransition
-                .getLastClipRevealMaxTranslation()) / (float) minimizeDistance;
-        final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
-                / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
-        return CLIP_REVEAL_MEET_EARLIEST
-                + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
-    }
-
-    public String toShortString() {
-        return TAG;
-    }
-
-    WindowState getWindow() {
-        return mWindow;
-    }
-
-    void dump(String prefix, PrintWriter pw) {
-        pw.println(prefix + "DockedStackDividerController");
-        pw.println(prefix + "  mLastVisibility=" + mLastVisibility);
-        pw.println(prefix + "  mMinimizedDock=" + mMinimizedDock);
-        pw.println(prefix + "  mAdjustedForIme=" + mAdjustedForIme);
-        pw.println(prefix + "  mAdjustedForDivider=" + mAdjustedForDivider);
-    }
-
-    void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(MINIMIZED_DOCK, mMinimizedDock);
-        proto.end(token);
-    }
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e69551a..54cea93 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -125,10 +125,6 @@
     // enabled for it to start intercepting touch events.
     private boolean mInputConsumerEnabled;
 
-    // Whether or not the recents animation should cause the primary split-screen stack to be
-    // minimized
-    private boolean mSplitScreenMinimized;
-
     private final Rect mTmpRect = new Rect();
 
     private boolean mLinkedToDeathOfRunner;
@@ -277,23 +273,6 @@
         }
 
         @Override
-        public void setSplitScreenMinimized(boolean minimized) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                synchronized (mService.getWindowManagerLock()) {
-                    if (mCanceled) {
-                        return;
-                    }
-
-                    mSplitScreenMinimized = minimized;
-                    mService.checkSplitScreenMinimizedChanged(true /* animate */);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void hideCurrentInputMethod() {
             final long token = Binder.clearCallingIdentity();
             try {
@@ -500,7 +479,7 @@
         }
 
         if (mTargetActivityRecord != null) {
-            final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(1);
+            final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>(1);
             reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM);
             mService.mAtmService.mStackSupervisor.getActivityMetricsLogger()
                     .notifyTransitionStarting(reasons);
@@ -738,10 +717,6 @@
         }
     }
 
-    boolean isSplitScreenMinimized() {
-        return mSplitScreenMinimized;
-    }
-
     boolean isWallpaperVisible(WindowState w) {
         return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION &&
                 ((w.mActivityRecord != null && mTargetActivityRecord == w.mActivityRecord)
@@ -944,7 +919,6 @@
         pw.print(innerPrefix); pw.println("mPendingAnimations=" + mPendingAnimations.size());
         pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
         pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
-        pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
         pw.print(innerPrefix); pw.println("mTargetActivityRecord=" + mTargetActivityRecord);
         pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
         pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index d2dbab8..0eb9daf 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -387,7 +387,7 @@
             final ActivityRecord topActivity = mWindowContainer.getTopMostActivity();
             if (dc.mOpeningApps.contains(topActivity)) {
                 return RemoteAnimationTarget.MODE_OPENING;
-            } else if (dc.mChangingApps.contains(topActivity)) {
+            } else if (dc.mChangingContainers.contains(topActivity)) {
                 return RemoteAnimationTarget.MODE_CHANGING;
             } else {
                 return RemoteAnimationTarget.MODE_CLOSING;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 64d7db2..ada5685 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -258,9 +258,6 @@
      */
     final ArrayList<ActivityTaskManagerInternal.SleepToken> mSleepTokens = new ArrayList<>();
 
-    /** Is dock currently minimized. */
-    boolean mIsDockMinimized;
-
     /** Set when a power hint has started, but not ended. */
     private boolean mPowerHintSent;
 
@@ -1011,9 +1008,7 @@
         // Send any pending task-info changes that were queued-up during a layout deferment
         mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
 
-        if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
-                "performSurfacePlacementInner exit: animating="
-                        + mWmService.mAnimator.isAnimating());
+        if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit");
     }
 
     private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
@@ -1989,8 +1984,7 @@
         // We dismiss the docked stack whenever we switch users.
         final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask();
         if (dockedStack != null) {
-            mStackSupervisor.moveTasksToFullscreenStackLocked(
-                    dockedStack, dockedStack.isFocusedStackOnDisplay());
+            getDefaultDisplay().onSplitScreenModeDismissed();
         }
         // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
         // also cause all tasks to be moved to the fullscreen stack at a position that is
@@ -2167,21 +2161,6 @@
         }
     }
 
-    void setDockedStackMinimized(boolean minimized) {
-        // Get currently focused stack before setting mIsDockMinimized. We do this because if
-        // split-screen is active, primary stack will not be focusable (see #isFocusable) while
-        // still occluding other stacks. This will cause getTopDisplayFocusedStack() to return null.
-        final ActivityStack current = getTopDisplayFocusedStack();
-        mIsDockMinimized = minimized;
-        if (mIsDockMinimized) {
-            if (current.inSplitScreenPrimaryWindowingMode()) {
-                // The primary split-screen stack can't be focused while it is minimize, so move
-                // focus to something else.
-                current.adjustFocusToNextFocusableStack("setDockedStackMinimized");
-            }
-        }
-    }
-
     ActivityRecord findTask(ActivityRecord r, int preferredDisplayId) {
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         mTmpFindTaskResult.clear();
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 7164cd8..1e54e69 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -128,7 +128,8 @@
      */
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
             @AnimationType int type,
-            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
+            @Nullable SurfaceFreezer freezer) {
         cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
         mAnimation = anim;
         mAnimationType = type;
@@ -139,9 +140,14 @@
             cancelAnimation();
             return;
         }
-        mLeash = createAnimationLeash(surface, t,
-                mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
-        mAnimatable.onAnimationLeashCreated(t, mLeash);
+        mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
+        if (mLeash == null) {
+            mLeash = createAnimationLeash(mAnimatable, surface, t,
+                    mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
+                    0 /* y */, hidden);
+            mAnimatable.onAnimationLeashCreated(t, mLeash);
+        }
+        mAnimatable.onLeashAnimationStarting(t, mLeash);
         if (mAnimationStartDelayed) {
             if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
             return;
@@ -150,6 +156,12 @@
     }
 
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+            @AnimationType int type,
+            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+        startAnimation(t, anim, hidden, type, animationFinishedCallback, null /* freezer */);
+    }
+
+    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
             @AnimationType int type) {
         startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
     }
@@ -311,15 +323,31 @@
     }
 
     private void reset(Transaction t, boolean destroyLeash) {
-        final SurfaceControl surface = mAnimatable.getSurfaceControl();
-        final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+        mService.mAnimationTransferMap.remove(mAnimation);
+        mAnimation = null;
+        mAnimationFinishedCallback = null;
+        mAnimationType = ANIMATION_TYPE_NONE;
+        if (mLeash == null) {
+            return;
+        }
+        SurfaceControl leash = mLeash;
+        mLeash = null;
+        final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
+        if (scheduleAnim) {
+            mService.scheduleAnimationLocked();
+        }
+    }
 
+    static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash,
+            boolean destroy) {
         boolean scheduleAnim = false;
+        final SurfaceControl surface = animatable.getSurfaceControl();
+        final SurfaceControl parent = animatable.getParentSurfaceControl();
 
         // If the surface was destroyed or the leash is invalid, we don't care to reparent it back.
         // Note that we also set this variable to true even if the parent isn't valid anymore, in
         // order to ensure onAnimationLeashLost still gets called in this case.
-        final boolean reparent = mLeash != null && surface != null;
+        final boolean reparent = surface != null;
         if (reparent) {
             if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
             // We shouldn't really need these isValid checks but we do
@@ -329,40 +357,30 @@
                 scheduleAnim = true;
             }
         }
-        mService.mAnimationTransferMap.remove(mAnimation);
-        if (mLeash != null && destroyLeash) {
-            t.remove(mLeash);
+        if (destroy) {
+            t.remove(leash);
             scheduleAnim = true;
         }
-        mLeash = null;
-        mAnimation = null;
-        mAnimationFinishedCallback = null;
-        mAnimationType = ANIMATION_TYPE_NONE;
 
         if (reparent) {
             // Make sure to inform the animatable after the surface was reparented (or reparent
             // wasn't possible, but we still need to invoke the callback)
-            mAnimatable.onAnimationLeashLost(t);
+            animatable.onAnimationLeashLost(t);
             scheduleAnim = true;
         }
-
-        if (scheduleAnim) {
-            mService.scheduleAnimationLocked();
-        }
+        return scheduleAnim;
     }
 
-    private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
-            int height, boolean hidden) {
+    static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
+            Transaction t, int width, int height, int x, int y, boolean hidden) {
         if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
-        final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
-                .setParent(mAnimatable.getAnimationLeashParent())
+        final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
+                .setParent(animatable.getAnimationLeashParent())
                 .setHidden(hidden)
                 .setName(surface + " - animation-leash");
         final SurfaceControl leash = builder.build();
         t.setWindowCrop(leash, width, height);
-
-        // TODO: rely on builder.setHidden(hidden) instead of show and setAlpha when b/138459974 is
-        //       fixed.
+        t.setPosition(leash, x, y);
         t.show(leash);
         t.setAlpha(leash, hidden ? 0 : 1);
 
@@ -489,7 +507,8 @@
         void commitPendingTransaction();
 
         /**
-         * Called when the was created.
+         * Called when the animation leash is created. Note that this is also called by
+         * {@link SurfaceFreezer}, so this doesn't mean we're about to start animating.
          *
          * @param t The transaction to use to apply any necessary changes.
          * @param leash The leash that was created.
@@ -497,6 +516,14 @@
         void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
 
         /**
+         * Called when the animator is about to start animating the leash.
+         *
+         * @param t The transaction to use to apply any necessary changes.
+         * @param leash The leash that was created.
+         */
+        default void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { }
+
+        /**
          * Called when the leash is being destroyed, or when the leash is being transferred to
          * another SurfaceAnimator.
          *
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
new file mode 100644
index 0000000..20435ea
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -0,0 +1,245 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+import com.android.server.protolog.common.ProtoLog;
+
+import java.util.function.Supplier;
+
+/**
+ * This class handles "freezing" of an Animatable. The Animatable in question should implement
+ * Freezable.
+ *
+ * The point of this is to enable WindowContainers to each be capable of freezing themselves.
+ * Freezing means taking a snapshot and placing it above everything in the sub-hierarchy.
+ * The "placing above" requires that a parent surface be inserted above the target surface so that
+ * the target surface and the snapshot are siblings.
+ *
+ * The overall flow for a transition using this would be:
+ * 1. Set transition and record animatable in mChangingApps
+ * 2. Call {@link #freeze} to set-up the leashes and cover with a snapshot.
+ * 3. When transition participants are ready, start SurfaceAnimator with this as a parameter
+ * 4. SurfaceAnimator will then {@link #takeLeashForAnimation} instead of creating another leash.
+ * 5. The animation system should eventually clean this up via {@link #unfreeze}.
+ */
+class SurfaceFreezer {
+
+    private final Freezable mAnimatable;
+    private final WindowManagerService mWmService;
+    private SurfaceControl mLeash;
+    Snapshot mSnapshot = null;
+    final Rect mFreezeBounds = new Rect();
+
+    /**
+     * @param animatable The object to animate.
+     */
+    SurfaceFreezer(Freezable animatable, WindowManagerService service) {
+        mAnimatable = animatable;
+        mWmService = service;
+    }
+
+    /**
+     * Freeze the target surface. This is done by creating a leash (inserting a parent surface
+     * above the target surface) and then taking a snapshot and placing it over the target surface.
+     *
+     * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
+     */
+    void freeze(SurfaceControl.Transaction t, Rect startBounds) {
+        mFreezeBounds.set(startBounds);
+
+        mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
+                t, startBounds.width(), startBounds.height(), startBounds.left, startBounds.top,
+                false /* hidden */);
+        mAnimatable.onAnimationLeashCreated(t, mLeash);
+
+        SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget();
+        if (freezeTarget != null) {
+            GraphicBuffer snapshot = createSnapshotBuffer(freezeTarget, startBounds);
+            if (snapshot != null) {
+                mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, snapshot, mLeash);
+            }
+        }
+    }
+
+    /**
+     * Used by {@link SurfaceAnimator}. This "transfers" the leash to be used for animation.
+     * By transferring the leash, this will no longer try to clean-up the leash when finished.
+     */
+    SurfaceControl takeLeashForAnimation() {
+        SurfaceControl out = mLeash;
+        mLeash = null;
+        return out;
+    }
+
+    /**
+     * Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the
+     * snapshot.
+     */
+    void unfreeze(SurfaceControl.Transaction t) {
+        if (mSnapshot != null) {
+            mSnapshot.destroy(t);
+        }
+        if (mLeash == null) {
+            return;
+        }
+        SurfaceControl leash = mLeash;
+        mLeash = null;
+        final boolean scheduleAnim = SurfaceAnimator.removeLeash(t, mAnimatable, leash,
+                false /* destroy */);
+        if (scheduleAnim) {
+            mWmService.scheduleAnimationLocked();
+        }
+    }
+
+    boolean hasLeash() {
+        return mLeash != null;
+    }
+
+    private static GraphicBuffer createSnapshotBuffer(@NonNull SurfaceControl target,
+            @Nullable Rect bounds) {
+        Rect cropBounds = null;
+        if (bounds != null) {
+            cropBounds = new Rect(bounds);
+            cropBounds.offsetTo(0, 0);
+        }
+        final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
+                SurfaceControl.captureLayers(
+                        target, cropBounds, 1.f /* frameScale */, PixelFormat.RGBA_8888);
+        final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
+                : null;
+        if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
+            return null;
+        }
+        return buffer;
+    }
+
+    class Snapshot {
+        private SurfaceControl mSurfaceControl;
+        private AnimationAdapter mAnimation;
+        private SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback;
+
+        /**
+         * @param t Transaction to create the thumbnail in.
+         * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
+         */
+        Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t,
+                GraphicBuffer thumbnailHeader, SurfaceControl parent) {
+            Surface drawSurface = surfaceFactory.get();
+            // We can't use a delegating constructor since we need to
+            // reference this::onAnimationFinished
+            final int width = thumbnailHeader.getWidth();
+            final int height = thumbnailHeader.getHeight();
+
+            mSurfaceControl = mAnimatable.makeAnimationLeash()
+                    .setName("snapshot anim: " + mAnimatable.toString())
+                    .setBufferSize(width, height)
+                    .setFormat(PixelFormat.TRANSLUCENT)
+                    .setParent(parent)
+                    .build();
+
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "  THUMBNAIL %s: CREATE", mSurfaceControl);
+
+            // Transfer the thumbnail to the surface
+            drawSurface.copyFrom(mSurfaceControl);
+            drawSurface.attachAndQueueBuffer(thumbnailHeader);
+            drawSurface.release();
+            t.show(mSurfaceControl);
+
+            // We parent the thumbnail to the container, and just place it on top of anything else
+            // in the container.
+            t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
+        }
+
+        void destroy(SurfaceControl.Transaction t) {
+            if (mSurfaceControl == null) {
+                return;
+            }
+            t.remove(mSurfaceControl);
+            mSurfaceControl = null;
+        }
+
+        /**
+         * Starts an animation.
+         *
+         * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
+         *             component responsible for running the animation. It runs the animation with
+         *             {@link AnimationAdapter#startAnimation} once the hierarchy with
+         *             the Leash has been set up.
+         * @param animationFinishedCallback The callback being triggered when the animation
+         *                                  finishes.
+         */
+        void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type,
+                @Nullable SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback) {
+            cancelAnimation(t, true /* restarting */);
+            mAnimation = anim;
+            mFinishedCallback = animationFinishedCallback;
+            if (mSurfaceControl == null) {
+                cancelAnimation(t, false /* restarting */);
+                return;
+            }
+            mAnimation.startAnimation(mSurfaceControl, t, type, animationFinishedCallback);
+        }
+
+        /**
+         * Cancels the animation, and resets the leash.
+         *
+         * @param t The transaction to use for all cancelling surface operations.
+         * @param restarting Whether we are restarting the animation.
+         */
+        private void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
+            final SurfaceControl leash = mSurfaceControl;
+            final AnimationAdapter animation = mAnimation;
+            final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback =
+                    mFinishedCallback;
+            mAnimation = null;
+            mFinishedCallback = null;
+            if (animation != null) {
+                animation.onAnimationCancelled(leash);
+                if (!restarting) {
+                    if (animationFinishedCallback != null) {
+                        animationFinishedCallback.onAnimationFinished(
+                                ANIMATION_TYPE_APP_TRANSITION, animation);
+                    }
+                }
+            }
+            if (!restarting) {
+                // TODO: do we need to destroy?
+                destroy(t);
+            }
+        }
+    }
+
+    /** freezable */
+    public interface Freezable extends SurfaceAnimator.Animatable {
+        /**
+         * @return The surface to take a snapshot of. If this returns {@code null}, no snapshot
+         *         will be generated (but the rest of the freezing logic will still happen).
+         */
+        @Nullable SurfaceControl getFreezeSnapshotTarget();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 76805e9..27acb23 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -58,6 +58,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
+import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
@@ -78,6 +79,9 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -119,10 +123,13 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
 import android.view.ITaskOrganizer;
+import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -1884,6 +1891,8 @@
                     .setBounds(mLastNonFullscreenBounds);
         }
 
+        final int prevWinMode = getWindowingMode();
+        mTmpPrevBounds.set(getBounds());
         final boolean wasInMultiWindowMode = inMultiWindowMode();
         super.onConfigurationChanged(newParentConfig);
         if (wasInMultiWindowMode != inMultiWindowMode()) {
@@ -1891,6 +1900,12 @@
             updateShadowsRadius(isFocused(), getPendingTransaction());
         }
 
+        final int newWinMode = getWindowingMode();
+        if ((prevWinMode != newWinMode) && (mDisplayContent != null)
+                && shouldStartChangeTransition(prevWinMode, newWinMode)) {
+            initializeChangeTransition(mTmpPrevBounds);
+        }
+
         // If the configuration supports persistent bounds (eg. Freeform), keep track of the
         // current (non-fullscreen) bounds for persistence.
         if (getWindowConfiguration().persistTaskBounds()) {
@@ -1905,6 +1920,63 @@
     }
 
     /**
+     * Initializes a change transition. See {@link SurfaceFreezer} for more information.
+     */
+    private void initializeChangeTransition(Rect startBounds) {
+        mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+                false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
+        mDisplayContent.mChangingContainers.add(this);
+
+        mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
+    }
+
+    private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
+        if (mWmService.mDisableTransitionAnimation
+                || !isVisible()
+                || getDisplayContent().mAppTransition.isTransitionSet()
+                || getSurfaceControl() == null) {
+            return false;
+        }
+        // Only do an animation into and out-of freeform mode for now. Other mode
+        // transition animations are currently handled by system-ui.
+        return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
+    }
+
+    @VisibleForTesting
+    boolean isInChangeTransition() {
+        return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit);
+    }
+
+    @Override
+    public SurfaceControl getFreezeSnapshotTarget() {
+        final int transit = mDisplayContent.mAppTransition.getAppTransition();
+        if (!AppTransition.isChangeTransit(transit)) {
+            return null;
+        }
+        // Skip creating snapshot if this transition is controlled by a remote animator which
+        // doesn't need it.
+        final ArraySet<Integer> activityTypes = new ArraySet<>();
+        activityTypes.add(getActivityType());
+        final RemoteAnimationAdapter adapter =
+                mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
+                        this, transit, activityTypes);
+        if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
+            return null;
+        }
+        return getSurfaceControl();
+    }
+
+    @Override
+    void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(HASH_CODE, System.identityHashCode(this));
+        proto.write(USER_ID, mUserId);
+        proto.write(TITLE, intent != null && intent.getComponent() != null
+                ? intent.getComponent().flattenToShortString() : "Task");
+        proto.end(token);
+    }
+
+    /**
      * Saves launching state if necessary so that we can launch the activity to its latest state.
      * It only saves state if this task has been shown to user and it's in fullscreen or freeform
      * mode on freeform displays.
@@ -2036,18 +2108,6 @@
         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
     }
 
-    /**
-     * Asks docked-divider controller for the smallestwidthdp given bounds.
-     * @param bounds bounds to calculate smallestwidthdp for.
-     */
-    private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
-        DisplayContent dc = getDisplayContent();
-        if (dc != null) {
-            return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
-        }
-        return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
-    }
-
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig) {
         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
@@ -2614,12 +2674,22 @@
         if (!isRootTask) {
             adjustBoundsForDisplayChangeIfNeeded(dc);
         }
+        final DisplayContent prevDc = mDisplayContent;
         super.onDisplayChanged(dc);
         if (!isRootTask) {
             final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
             mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
                     mTaskId, displayId);
         }
+        if (prevDc != null && prevDc.mChangingContainers.remove(this)) {
+            // This gets called *after* this has been reparented to the new display.
+            // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
+            // so this token is now "frozen" while waiting for the animation to start on prevDc
+            // (which will be cancelled since the window is no-longer a child). However, since this
+            // is no longer a child of prevDc, this won't be notified of the cancelled animation,
+            // so we need to cancel the change transition here.
+            mSurfaceFreezer.unfreeze(getPendingTransaction());
+        }
     }
 
     /**
@@ -3010,15 +3080,6 @@
         return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); });
     }
 
-    /**
-     * @return {@code true} if changing app transition is running.
-     */
-    @Override
-    boolean isChangingAppTransition() {
-        final ActivityRecord activity = getTopVisibleActivity();
-        return activity != null && getDisplayContent().mChangingApps.contains(activity);
-    }
-
     @Override
     RemoteAnimationTarget createRemoteAnimationTarget(
             RemoteAnimationController.RemoteAnimationRecord record) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 5c73f92..f83b052 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -18,19 +18,18 @@
 
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 
-import static com.android.server.wm.TaskSnapshotPersister.DISABLE_HIGH_RES_BITMAPS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -89,14 +88,6 @@
     @VisibleForTesting
     static final int SNAPSHOT_MODE_NONE = 2;
 
-    /**
-     * Constant for <code>scaleFactor</code> when calling {@link #snapshotTask} which is
-     * interpreted as using the most appropriate scale ratio for the system.
-     * This may yield a smaller ratio on low memory devices.
-     */
-    @VisibleForTesting
-    static final float SNAPSHOT_SCALE_AUTO = -1f;
-
     private final WindowManagerService mService;
 
     private final TaskSnapshotCache mCache;
@@ -229,7 +220,7 @@
     @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk,
             boolean isLowResolution) {
         return mCache.getSnapshot(taskId, userId, restoreFromDisk, isLowResolution
-                || DISABLE_HIGH_RES_BITMAPS);
+                && mPersister.enableLowResSnapshots());
     }
 
     /**
@@ -273,8 +264,6 @@
      * information from the task and populates the builder.
      *
      * @param task the task to capture
-     * @param scaleFraction the scale fraction between 0-1.0, or {@link #SNAPSHOT_SCALE_AUTO}
-     *                      to automatically select
      * @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to
      *                    automatically select
      * @param builder the snapshot builder to populate
@@ -282,8 +271,7 @@
      * @return true if the state of the task is ok to proceed
      */
     @VisibleForTesting
-    boolean prepareTaskSnapshot(Task task, float scaleFraction, int pixelFormat,
-            TaskSnapshot.Builder builder) {
+    boolean prepareTaskSnapshot(Task task, int pixelFormat, TaskSnapshot.Builder builder) {
         if (!mService.mPolicy.isScreenOn()) {
             if (DEBUG_SCREENSHOT) {
                 Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
@@ -314,18 +302,6 @@
         builder.setId(System.currentTimeMillis());
         builder.setContentInsets(getInsets(mainWindow));
 
-        final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-
-        if (scaleFraction == SNAPSHOT_SCALE_AUTO) {
-            builder.setScaleFraction(isLowRamDevice
-                    ? mPersister.getLowResScale()
-                    : mHighResTaskSnapshotScale);
-            builder.setIsLowResolution(isLowRamDevice);
-        } else {
-            builder.setScaleFraction(scaleFraction);
-            builder.setIsLowResolution(scaleFraction < 1.0f);
-        }
-
         final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
         final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
 
@@ -351,13 +327,23 @@
 
     @Nullable
     SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
-            float scaleFraction) {
-        return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888);
+            TaskSnapshot.Builder builder) {
+        Point taskSize = new Point();
+        final SurfaceControl.ScreenshotGraphicBuffer taskSnapshot = createTaskSnapshot(task,
+                mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize);
+        builder.setTaskSize(taskSize);
+        return taskSnapshot;
     }
 
     @Nullable
     SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
-            float scaleFraction, int pixelFormat) {
+            float scaleFraction) {
+        return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null);
+    }
+
+    @Nullable
+    SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
+            float scaleFraction, int pixelFormat, Point outTaskSize) {
         if (task.getSurfaceControl() == null) {
             if (DEBUG_SCREENSHOT) {
                 Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -369,6 +355,10 @@
         final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
                 SurfaceControl.captureLayers(
                         task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat);
+        if (outTaskSize != null) {
+            outTaskSize.x = mTmpRect.width();
+            outTaskSize.y = mTmpRect.height();
+        }
         final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
                 : null;
         if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -379,21 +369,20 @@
 
     @Nullable
     TaskSnapshot snapshotTask(Task task) {
-        return snapshotTask(task, SNAPSHOT_SCALE_AUTO, PixelFormat.UNKNOWN);
+        return snapshotTask(task, PixelFormat.UNKNOWN);
     }
 
     @Nullable
-    TaskSnapshot snapshotTask(Task task, float scaleFraction, int pixelFormat) {
+    TaskSnapshot snapshotTask(Task task, int pixelFormat) {
         TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
 
-        if (!prepareTaskSnapshot(task, scaleFraction, pixelFormat, builder)) {
+        if (!prepareTaskSnapshot(task, pixelFormat, builder)) {
             // Failed some pre-req. Has been logged.
             return null;
         }
 
         final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
-                createTaskSnapshot(task, builder.getScaleFraction(),
-                builder.getPixelFormat());
+                createTaskSnapshot(task, builder);
 
         if (screenshotBuffer == null) {
             // Failed to acquire image. Has been logged.
@@ -472,8 +461,10 @@
         final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
                 mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState());
-        final int width = (int) (task.getBounds().width() * mHighResTaskSnapshotScale);
-        final int height = (int) (task.getBounds().height() * mHighResTaskSnapshotScale);
+        final int taskWidth = task.getBounds().width();
+        final int taskHeight = task.getBounds().height();
+        final int width = (int) (taskWidth * mHighResTaskSnapshotScale);
+        final int height = (int) (taskHeight * mHighResTaskSnapshotScale);
 
         final RenderNode node = RenderNode.create("TaskSnapshotController", null);
         node.setLeftTopRightBottom(0, 0, width, height);
@@ -494,9 +485,9 @@
                 System.currentTimeMillis() /* id */,
                 topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(),
                 hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
-                mainWindow.getWindowConfiguration().getRotation(),
-                getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* isLowResolution */,
-                mHighResTaskSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(),
+                mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
+                getInsets(mainWindow), false /* isLowResolution */,
+                false /* isRealSnapshot */, task.getWindowingMode(),
                 getSystemUiVisibility(task), false);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 01f3427..c20ce5f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -19,6 +19,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.ComponentName;
 import android.graphics.Bitmap;
@@ -26,6 +27,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapFactory.Options;
 import android.graphics.GraphicBuffer;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.Slog;
 
@@ -52,28 +54,110 @@
         mPersister = persister;
     }
 
+    static class PreRLegacySnapshotConfig {
+        /**
+         * If isPreRLegacy is {@code true}, specifies the scale the snapshot was taken at
+         */
+        final float mScale;
+
+        /**
+         * If {@code true}, always load *_reduced.jpg file, no matter what was requested
+         */
+        final boolean mForceLoadReducedJpeg;
+
+        PreRLegacySnapshotConfig(float scale, boolean forceLoadReducedJpeg) {
+            mScale = scale;
+            mForceLoadReducedJpeg = forceLoadReducedJpeg;
+        }
+    }
+
+    /**
+     * When device is upgraded, we might be loading a legacy snapshot. In those cases,
+     * restore the scale based on how it was configured historically. See history of
+     * TaskSnapshotPersister for more information.
+     *
+     *   | low_ram=false                      | low_ram=true
+     *   +------------------------------------------------------------------------------+
+     * O | *.jpg = 100%, *_reduced.jpg = 50%                                            |
+     *   |                                    +-----------------------------------------|
+     * P |                                    | *.jpg = NONE, *_reduced.jpg = 60%       |
+     *   +------------------------------------+-----------------------------------------+
+     * Q | *.jpg = proto.scale,               | *.jpg = NONE,                           |
+     *   | *_reduced.jpg = 50% * proto.scale  | *_reduced.jpg = proto.scale             |
+     *   +------------------------------------+-----------------------------------------+
+     *
+     * @return null if Android R, otherwise a PreRLegacySnapshotConfig object
+     */
+    PreRLegacySnapshotConfig getLegacySnapshotConfig(int taskWidth, float legacyScale,
+            boolean highResFileExists, boolean loadLowResolutionBitmap) {
+        float preRLegacyScale = 0;
+        boolean forceLoadReducedJpeg = false;
+        boolean isPreRLegacySnapshot = (taskWidth == 0);
+        if (!isPreRLegacySnapshot) {
+            return null;
+        }
+        final boolean isPreQLegacyProto = isPreRLegacySnapshot
+                && (Float.compare(legacyScale, 0f) == 0);
+
+        if (isPreQLegacyProto) {
+            // Android O or Android P
+            if (ActivityManager.isLowRamDeviceStatic() && !highResFileExists) {
+                // Android P w/ low_ram=true
+                preRLegacyScale = 0.6f;
+                // Force bitmapFile to always be *_reduced.jpg
+                forceLoadReducedJpeg = true;
+            } else {
+                // Android O, OR Android P w/ low_ram=false
+                preRLegacyScale = loadLowResolutionBitmap ? 0.5f : 1.0f;
+            }
+        } else if (isPreRLegacySnapshot) {
+            // If not pre-Q but is pre-R, then it must be Android Q
+            if (ActivityManager.isLowRamDeviceStatic()) {
+                preRLegacyScale = legacyScale;
+                // Force bitmapFile to always be *_reduced.jpg
+                forceLoadReducedJpeg = true;
+            } else {
+                preRLegacyScale =
+                        loadLowResolutionBitmap ? 0.5f * legacyScale : legacyScale;
+            }
+        }
+        return new PreRLegacySnapshotConfig(preRLegacyScale, forceLoadReducedJpeg);
+    }
+
     /**
      * Loads a task from the disk.
      * <p>
      * Do not hold the window manager lock when calling this method, as we directly read data from
      * disk here, which might be slow.
      *
-     * @param taskId The id of the task to load.
-     * @param userId The id of the user the task belonged to.
-     * @param isLowResolution Whether to load a reduced resolution version of the snapshot.
+     * @param taskId                  The id of the task to load.
+     * @param userId                  The id of the user the task belonged to.
+     * @param loadLowResolutionBitmap Whether to load a low resolution resolution version of the
+     *                                snapshot.
      * @return The loaded {@link TaskSnapshot} or {@code null} if it couldn't be loaded.
      */
-    TaskSnapshot loadTask(int taskId, int userId, boolean isLowResolution) {
+    TaskSnapshot loadTask(int taskId, int userId, boolean loadLowResolutionBitmap) {
         final File protoFile = mPersister.getProtoFile(taskId, userId);
-        final File bitmapFile = isLowResolution
-                ? mPersister.getLowResolutionBitmapFile(taskId, userId)
-                : mPersister.getHighResolutionBitmapFile(taskId, userId);
-        if (bitmapFile == null || !protoFile.exists() || !bitmapFile.exists()) {
+        if (!protoFile.exists()) {
             return null;
         }
         try {
             final byte[] bytes = Files.readAllBytes(protoFile.toPath());
             final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
+            final File highResBitmap = mPersister.getHighResolutionBitmapFile(taskId, userId);
+
+            PreRLegacySnapshotConfig legacyConfig = getLegacySnapshotConfig(proto.taskWidth,
+                    proto.legacyScale, highResBitmap.exists(), loadLowResolutionBitmap);
+
+            boolean forceLoadReducedJpeg =
+                    legacyConfig != null && legacyConfig.mForceLoadReducedJpeg;
+            File bitmapFile = (loadLowResolutionBitmap || forceLoadReducedJpeg)
+                    ? mPersister.getLowResolutionBitmapFile(taskId, userId) : highResBitmap;
+
+            if (!bitmapFile.exists()) {
+                return null;
+            }
+
             final Options options = new Options();
             options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent
                     ? Config.RGB_565
@@ -99,13 +183,20 @@
 
             final ComponentName topActivityComponent = ComponentName.unflattenFromString(
                     proto.topActivityComponent);
-            // For legacy snapshots, restore the scale based on the reduced resolution state
-            final float legacyScale = isLowResolution ? mPersister.getLowResScale() : 1f;
-            final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale;
-            return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(),
-                    proto.orientation, proto.rotation,
+
+            Point taskSize;
+            if (legacyConfig != null) {
+                int taskWidth = (int) ((float) hwBitmap.getWidth() / legacyConfig.mScale);
+                int taskHeight = (int) ((float) hwBitmap.getHeight() / legacyConfig.mScale);
+                taskSize = new Point(taskWidth, taskHeight);
+            } else {
+                taskSize = new Point(proto.taskWidth, proto.taskHeight);
+            }
+
+            return new TaskSnapshot(proto.id, topActivityComponent, buffer,
+                    hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize,
                     new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
-                    isLowResolution, scale, proto.isRealSnapshot, proto.windowingMode,
+                    loadLowResolutionBitmap, proto.isRealSnapshot, proto.windowingMode,
                     proto.systemUiVisibility, proto.isTranslucent);
         } catch (IOException e) {
             Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 31212b8..164d3e0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -21,8 +21,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -52,8 +52,6 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
     private static final String SNAPSHOTS_DIRNAME = "snapshots";
     private static final String LOW_RES_FILE_POSTFIX = "_reduced";
-    private static final float LOW_RAM_REDUCED_SCALE = .8f;
-    static final boolean DISABLE_HIGH_RES_BITMAPS = ActivityManager.isLowRamDeviceStatic();
     private static final long DELAY_MS = 100;
     private static final int QUALITY = 95;
     private static final String PROTO_EXTENSION = ".proto";
@@ -71,7 +69,8 @@
     private boolean mStarted;
     private final Object mLock = new Object();
     private final DirectoryResolver mDirectoryResolver;
-    private final float mLowResScale;
+    private final float mLowResScaleFactor;
+    private boolean mEnableLowResSnapshots;
     private final boolean mUse16BitFormat;
 
     /**
@@ -83,13 +82,29 @@
 
     TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
         mDirectoryResolver = resolver;
+        final float highResTaskSnapshotScale = service.mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_highResTaskSnapshotScale);
+        final float lowResTaskSnapshotScale = service.mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_lowResTaskSnapshotScale);
 
-        if (ActivityManager.isLowRamDeviceStatic()) {
-            mLowResScale = LOW_RAM_REDUCED_SCALE;
-        } else {
-            mLowResScale = service.mContext.getResources().getFloat(
-                    com.android.internal.R.dimen.config_lowResTaskSnapshotScale);
+        if (lowResTaskSnapshotScale < 0 || 1 <= lowResTaskSnapshotScale) {
+            throw new RuntimeException("Low-res scale must be between 0 and 1");
         }
+        if (highResTaskSnapshotScale <= 0 || 1 < highResTaskSnapshotScale) {
+            throw new RuntimeException("High-res scale must be between 0 and 1");
+        }
+        if (highResTaskSnapshotScale <= lowResTaskSnapshotScale) {
+            throw new RuntimeException("High-res scale must be greater than low-res scale");
+        }
+
+        if (lowResTaskSnapshotScale > 0) {
+            mLowResScaleFactor = lowResTaskSnapshotScale / highResTaskSnapshotScale;
+            setEnableLowResSnapshots(true);
+        } else {
+            mLowResScaleFactor = 0;
+            setEnableLowResSnapshots(false);
+        }
+
         mUse16BitFormat = service.mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
     }
@@ -155,13 +170,16 @@
         }
     }
 
+    boolean enableLowResSnapshots() {
+        return mEnableLowResSnapshots;
+    }
+
     /**
-     * Gets the scaling the persister uses for low resolution task snapshots.
-     *
-     * @return the lowResBitmap scale of task snapshots when they are set to be low res
+     * Not to be used. Only here for testing.
      */
-    float getLowResScale() {
-        return mLowResScale;
+    @VisibleForTesting
+    void setEnableLowResSnapshots(boolean enabled) {
+        mEnableLowResSnapshots = enabled;
     }
 
     /**
@@ -213,14 +231,10 @@
     }
 
     File getHighResolutionBitmapFile(int taskId, int userId) {
-        // Full sized bitmaps are disabled on low ram devices
-        if (DISABLE_HIGH_RES_BITMAPS) {
-            Slog.wtf(TAG, "This device does not support full sized resolution bitmaps.");
-            return null;
-        }
         return new File(getDirectory(userId), taskId + BITMAP_EXTENSION);
     }
 
+    @NonNull
     File getLowResolutionBitmapFile(int taskId, int userId) {
         return new File(getDirectory(userId), taskId + LOW_RES_FILE_POSTFIX + BITMAP_EXTENSION);
     }
@@ -234,11 +248,11 @@
         final File protoFile = getProtoFile(taskId, userId);
         final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId);
         protoFile.delete();
-        bitmapLowResFile.delete();
-
-        // Low ram devices do not have a full sized file to delete
-        if (!DISABLE_HIGH_RES_BITMAPS) {
-            final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
+        if (bitmapLowResFile.exists()) {
+            bitmapLowResFile.delete();
+        }
+        final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
+        if (bitmapFile.exists()) {
             bitmapFile.delete();
         }
     }
@@ -343,6 +357,8 @@
             final TaskSnapshotProto proto = new TaskSnapshotProto();
             proto.orientation = mSnapshot.getOrientation();
             proto.rotation = mSnapshot.getRotation();
+            proto.taskWidth = mSnapshot.getTaskSize().x;
+            proto.taskHeight = mSnapshot.getTaskSize().y;
             proto.insetLeft = mSnapshot.getContentInsets().left;
             proto.insetTop = mSnapshot.getContentInsets().top;
             proto.insetRight = mSnapshot.getContentInsets().right;
@@ -352,7 +368,6 @@
             proto.systemUiVisibility = mSnapshot.getSystemUiVisibility();
             proto.isTranslucent = mSnapshot.isTranslucent();
             proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString();
-            proto.scale = mSnapshot.getScale();
             proto.id = mSnapshot.getId();
             final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
             final File file = getProtoFile(mTaskId, mUserId);
@@ -379,11 +394,26 @@
             }
 
             final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */);
-            final Bitmap lowResBitmap = mSnapshot.isLowResolution()
-                    ? swBitmap
-                    : Bitmap.createScaledBitmap(swBitmap,
-                            (int) (bitmap.getWidth() * mLowResScale),
-                            (int) (bitmap.getHeight() * mLowResScale), true /* filter */);
+
+            final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
+            try {
+                FileOutputStream fos = new FileOutputStream(file);
+                swBitmap.compress(JPEG, QUALITY, fos);
+                fos.close();
+            } catch (IOException e) {
+                Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
+                return false;
+            }
+
+            if (!enableLowResSnapshots()) {
+                swBitmap.recycle();
+                return true;
+            }
+
+            final Bitmap lowResBitmap = Bitmap.createScaledBitmap(swBitmap,
+                    (int) (bitmap.getWidth() * mLowResScaleFactor),
+                    (int) (bitmap.getHeight() * mLowResScaleFactor), true /* filter */);
+            swBitmap.recycle();
 
             final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId);
             try {
@@ -396,22 +426,6 @@
             }
             lowResBitmap.recycle();
 
-            // For snapshots with lowResBitmap resolution, do not create or save full sized bitmaps
-            if (mSnapshot.isLowResolution()) {
-                swBitmap.recycle();
-                return true;
-            }
-
-            final File file = getHighResolutionBitmapFile(mTaskId, mUserId);
-            try {
-                FileOutputStream fos = new FileOutputStream(file);
-                swBitmap.compress(JPEG, QUALITY, fos);
-                fos.close();
-            } catch (IOException e) {
-                Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
-                return false;
-            }
-            swBitmap.recycle();
             return true;
         }
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index f4e4245..eb005e0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -36,6 +36,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
 import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
 import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
 import static com.android.internal.policy.DecorView.getColorViewLeftInset;
@@ -53,9 +54,11 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -131,6 +134,8 @@
     private final Rect mContentInsets = new Rect();
     private final Rect mFrame = new Rect();
     private TaskSnapshot mSnapshot;
+    private final RectF mTmpSnapshotSize = new RectF();
+    private final RectF mTmpDstFrame = new RectF();
     private final CharSequence mTitle;
     private boolean mHasDrawn;
     private long mShownTime;
@@ -141,6 +146,8 @@
     @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
     private final int mOrientationOnCreation;
     private final SurfaceControl.Transaction mTransaction;
+    private final Matrix mSnapshotMatrix = new Matrix();
+    private final float[] mTmpFloat9 = new float[9];
 
     static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
             TaskSnapshot snapshot) {
@@ -365,13 +372,17 @@
             frame = calculateSnapshotFrame(crop);
             mTransaction.setWindowCrop(mChildSurfaceControl, crop);
             mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
+            mTmpDstFrame.set(frame);
         } else {
             frame = null;
+            mTmpDstFrame.set(mFrame);
         }
 
         // Scale the mismatch dimensions to fill the task bounds
-        final float scale = 1 / mSnapshot.getScale();
-        mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale);
+        mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+        mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
+        mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+
         mTransaction.apply();
         surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
         surface.release();
@@ -395,13 +406,17 @@
         rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
         final Rect insets = mSnapshot.getContentInsets();
 
+        final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x;
+        final float scaleY =
+                (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y;
+
         // Let's remove all system decorations except the status bar, but only if the task is at the
         // very top of the screen.
         final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
-        rect.inset((int) (insets.left * mSnapshot.getScale()),
-                isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
-                (int) (insets.right * mSnapshot.getScale()),
-                (int) (insets.bottom * mSnapshot.getScale()));
+        rect.inset((int) (insets.left * scaleX),
+                isTop ? 0 : (int) (insets.top * scaleY),
+                (int) (insets.right * scaleX),
+                (int) (insets.bottom * scaleY));
         return rect;
     }
 
@@ -412,14 +427,20 @@
      */
     @VisibleForTesting
     Rect calculateSnapshotFrame(Rect crop) {
-        final Rect frame = new Rect(crop);
-        final float scale = mSnapshot.getScale();
+        final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x;
+        final float scaleY =
+                (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y;
 
         // Rescale the frame from snapshot to window coordinate space
-        frame.scale(1 / scale);
+        final Rect frame = new Rect(
+                (int) (crop.left / scaleX + 0.5f),
+                (int) (crop.top / scaleY + 0.5f),
+                (int) (crop.right / scaleX + 0.5f),
+                (int) (crop.bottom / scaleY + 0.5f)
+        );
 
         // By default, offset it to to top/left corner
-        frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
+        frame.offsetTo((int) (-crop.left / scaleX), (int) (-crop.top / scaleY));
 
         // However, we also need to make space for the navigation bar on the left side.
         final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 137d122..669eb78 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -669,8 +669,7 @@
      * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
      * the opening apps should be a wallpaper target.
      */
-    void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps,
-            ArraySet<ActivityRecord> changingApps) {
+    void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps) {
         boolean adjust = false;
         if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
             adjust = true;
@@ -682,15 +681,6 @@
                     break;
                 }
             }
-            if (!adjust) {
-                for (int i = changingApps.size() - 1; i >= 0; --i) {
-                    final ActivityRecord activity = changingApps.valueAt(i);
-                    if (activity.windowsCanBeWallpaperTarget()) {
-                        adjust = true;
-                        break;
-                    }
-                }
-            }
         }
 
         if (adjust) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index fd91bc5..b6be386 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -50,7 +50,6 @@
     final WindowManagerPolicy mPolicy;
 
     /** Is any window animating? */
-    private boolean mAnimating;
     private boolean mLastRootAnimating;
 
     final Choreographer.FrameCallback mAnimationFrameCallback;
@@ -135,7 +134,6 @@
         synchronized (mService.mGlobalLock) {
             mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
             mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
-            mAnimating = false;
             if (DEBUG_WINDOW_TRACE) {
                 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
             }
@@ -160,17 +158,12 @@
                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
 
                     dc.checkAppWindowsReadyToShow();
-                    orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
                     if (accessibilityController != null) {
                         accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
                                 mTransaction);
                     }
                 }
 
-                if (!mAnimating) {
-                    cancelAnimation();
-                }
-
                 if (mService.mWatermark != null) {
                     mService.mWatermark.drawIfNeeded();
                 }
@@ -220,7 +213,7 @@
             executeAfterPrepareSurfacesRunnables();
 
             if (DEBUG_WINDOW_TRACE) {
-                Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
+                Slog.i(TAG, "!!! animate: exit"
                         + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
                         + " hasPendingLayoutChanges=" + hasPendingLayoutChanges);
             }
@@ -302,10 +295,6 @@
     private class DisplayContentsAnimator {
     }
 
-    boolean isAnimating() {
-        return mAnimating;
-    }
-
     boolean isAnimationScheduled() {
         return mAnimationFrameCallbackScheduled;
     }
@@ -314,14 +303,6 @@
         return mChoreographer;
     }
 
-    void setAnimating(boolean animating) {
-        mAnimating = animating;
-    }
-
-    void orAnimating(boolean animating) {
-        mAnimating |= animating;
-    }
-
     /**
      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
      * the corresponding transaction is closed and applied.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index aaaabf2..a0a70dc 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -25,9 +25,13 @@
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.os.UserHandle.USER_NULL;
 import static android.view.SurfaceControl.Transaction;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -64,6 +68,7 @@
 import android.view.DisplayInfo;
 import android.view.IWindowContainer;
 import android.view.MagnificationSpec;
+import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Builder;
@@ -94,7 +99,7 @@
  * changes are made to this class.
  */
 class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
-        implements Comparable<WindowContainer>, Animatable,
+        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
                    BLASTSyncEngine.TransactionReadyListener {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
@@ -169,6 +174,7 @@
      * Applied as part of the animation pass in "prepareSurfaces".
      */
     protected final SurfaceAnimator mSurfaceAnimator;
+    final SurfaceFreezer mSurfaceFreezer;
     protected final WindowManagerService mWmService;
 
     private final Point mTmpPos = new Point();
@@ -252,7 +258,6 @@
      * where it represents the starting-state snapshot.
      */
     WindowContainerThumbnail mThumbnail;
-    final Rect mTransitStartRect = new Rect();
     final Point mTmpPoint = new Point();
     protected final Rect mTmpRect = new Rect();
     final Rect mTmpPrevBounds = new Rect();
@@ -277,6 +282,7 @@
         mWmService = wms;
         mPendingTransaction = wms.mTransactionFactory.get();
         mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
+        mSurfaceFreezer = new SurfaceFreezer(this, wms);
     }
 
     @Override
@@ -834,7 +840,7 @@
      * @return {@code true} if the container is in changing app transition.
      */
     boolean isChangingAppTransition() {
-        return false;
+        return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
     }
 
     void sendAppVisibilityToClients() {
@@ -886,6 +892,31 @@
     }
 
     /**
+     * Called when the visibility of a child is asked to change. This is before visibility actually
+     * changes (eg. a transition animation might play out first).
+     */
+    void onChildVisibilityRequested(boolean visible) {
+        // If we are changing visibility, then a snapshot isn't necessary and we are no-longer
+        // part of a change transition.
+        mSurfaceFreezer.unfreeze(getPendingTransaction());
+        if (mDisplayContent != null) {
+            mDisplayContent.mChangingContainers.remove(this);
+        }
+        WindowContainer parent = getParent();
+        if (parent != null) {
+            parent.onChildVisibilityRequested(visible);
+        }
+    }
+
+    void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(HASH_CODE, System.identityHashCode(this));
+        proto.write(USER_ID, USER_NULL);
+        proto.write(TITLE, "WindowContainer");
+        proto.end(token);
+    }
+
+    /**
      * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable,
      * this will not be focusable either.
      */
@@ -1917,7 +1948,8 @@
 
         // TODO: This should use isVisible() but because isVisible has a really weird meaning at
         // the moment this doesn't work for all animatable window containers.
-        mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback);
+        mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
+                mSurfaceFreezer);
     }
 
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@@ -1934,6 +1966,11 @@
     }
 
     @Override
+    public SurfaceControl getFreezeSnapshotTarget() {
+        return null;
+    }
+
+    @Override
     public Builder makeAnimationLeash() {
         return makeSurface().setContainerLayer();
     }
@@ -2002,8 +2039,9 @@
                         getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                     }
                     if (thumbnailAdapter != null) {
-                        mThumbnail.startAnimation(
-                                getPendingTransaction(), thumbnailAdapter, !isVisible());
+                        mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
+                                thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION,
+                                (type, anim) -> { });
                     }
                 }
             } else {
@@ -2049,7 +2087,7 @@
         if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
             final RemoteAnimationController.RemoteAnimationRecord adapters =
                     controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
-                            (isChanging ? mTransitStartRect : null));
+                            (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
             resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
         } else if (isChanging) {
             final float durationScale = mWmService.getTransitionAnimationScaleLocked();
@@ -2057,14 +2095,15 @@
             mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
 
             final AnimationAdapter adapter = new LocalAnimationAdapter(
-                    new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
-                            durationScale, true /* isAppAnimation */, false /* isThumbnail */),
+                    new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect,
+                            displayInfo, durationScale, true /* isAppAnimation */,
+                            false /* isThumbnail */),
                     getSurfaceAnimationRunner());
 
-            final AnimationAdapter thumbnailAdapter = mThumbnail != null
-                    ? new LocalAnimationAdapter(new WindowChangeAnimationSpec(mTransitStartRect,
-                    mTmpRect, displayInfo, durationScale, true /* isAppAnimation */,
-                    true /* isThumbnail */), getSurfaceAnimationRunner())
+            final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null
+                    ? new LocalAnimationAdapter(new WindowChangeAnimationSpec(
+                    mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale,
+                    true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner())
                     : null;
             resultAdapters = new Pair<>(adapter, thumbnailAdapter);
             mTransit = transit;
@@ -2182,6 +2221,7 @@
     @Override
     public void onAnimationLeashLost(Transaction t) {
         mLastLayer = -1;
+        mSurfaceFreezer.unfreeze(t);
         reassignLayer(t);
     }
 
@@ -2322,6 +2362,10 @@
         mSurfaceControl = sc;
     }
 
+    RemoteAnimationDefinition getRemoteAnimationDefinition() {
+        return null;
+    }
+
     /** Cheap way of doing cast and instanceof. */
     Task asTask() {
         return null;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e0f8f0e..a59eab5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -42,7 +42,6 @@
 import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -59,7 +58,6 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -214,7 +212,6 @@
 import android.view.IDisplayWindowInsetsController;
 import android.view.IDisplayWindowListener;
 import android.view.IDisplayWindowRotationController;
-import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IPinnedStackListener;
@@ -1636,14 +1633,6 @@
                 }
             }
 
-            // If the window is being added to a stack that's currently adjusted for IME,
-            // make sure to apply the same adjust to this new window.
-            win.applyAdjustForImeIfNeeded();
-
-            if (type == TYPE_DOCK_DIVIDER) {
-                mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);
-            }
-
             final WindowStateAnimator winAnimator = win.mWinAnimator;
             winAnimator.mEnterAnimationPending = true;
             winAnimator.mEnteringAnimation = true;
@@ -2816,16 +2805,6 @@
         }
     }
 
-    void setDockedStackCreateStateLocked(int mode, Rect bounds) {
-        mDockedStackCreateMode = mode;
-        mDockedStackCreateBounds = bounds;
-    }
-
-    void checkSplitScreenMinimizedChanged(boolean animate) {
-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
-        displayContent.getDockedDividerController().checkMinimizeChanged(animate);
-    }
-
     boolean isValidPictureInPictureAspectRatio(DisplayContent displayContent, float aspectRatio) {
         return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
                 aspectRatio);
@@ -3295,10 +3274,6 @@
 
             // Notify whether the docked stack exists for the current user
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final ActivityStack stack =
-                    displayContent.getRootSplitScreenPrimaryTask();
-            displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
-                    stack != null && stack.hasTaskForUser(newUserId));
 
             mRoot.forAllDisplays(dc -> dc.mAppTransition.setCurrentUser(newUserId));
 
@@ -4687,7 +4662,7 @@
         public static final int RESET_ANR_MESSAGE = 38;
         public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39;
 
-        public static final int UPDATE_DOCKED_STACK_DIVIDER = 41;
+        public static final int UPDATE_MULTI_WINDOW_STACKS = 41;
 
         public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
 
@@ -4832,7 +4807,7 @@
                     synchronized (mGlobalLock) {
                         // Since we're holding both mWindowMap and mAnimator we don't need to
                         // hold mAnimator.mLayoutToAnim.
-                        if (mAnimator.isAnimating() || mAnimator.isAnimationScheduled()) {
+                        if (mAnimator.isAnimationScheduled()) {
                             // If we are animating, don't do the gc now but
                             // delay a bit so we don't interrupt the animation.
                             sendEmptyMessageDelayed(H.FORCE_GC, 2000);
@@ -4994,11 +4969,10 @@
                     }
                     break;
                 }
-                case UPDATE_DOCKED_STACK_DIVIDER: {
+                case UPDATE_MULTI_WINDOW_STACKS: {
                     synchronized (mGlobalLock) {
                         final DisplayContent displayContent = getDefaultDisplayContentLocked();
                         if (displayContent != null) {
-                            displayContent.getDockedDividerController().reevaluateVisibility(false);
                             displayContent.adjustForImeIfNeeded();
                         }
                     }
@@ -6551,11 +6525,7 @@
 
     @Override
     public int getDockedStackSide() {
-        synchronized (mGlobalLock) {
-            final ActivityStack dockedStack = getDefaultDisplayContentLocked()
-                    .getRootSplitScreenPrimaryTask();
-            return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
-        }
+        return 0;
     }
 
     void setDockedStackResizing(boolean resizing) {
@@ -6572,14 +6542,6 @@
         }
     }
 
-    @Override
-    public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
-        synchronized (mGlobalLock) {
-            getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
-                    visible, targetWindowingMode, alpha);
-        }
-    }
-
     void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
         synchronized (mGlobalLock) {
             mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
@@ -6598,17 +6560,6 @@
     }
 
     @Override
-    public void registerDockedStackListener(IDockedStackListener listener) {
-        mAtmInternal.enforceCallerIsRecentsOrHasPermission(REGISTER_WINDOW_MANAGER_LISTENERS,
-                "registerDockedStackListener()");
-        synchronized (mGlobalLock) {
-            // TODO(multi-display): The listener is registered on the default display only.
-            getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
-                    listener);
-        }
-    }
-
-    @Override
     public void registerPinnedStackListener(int displayId, IPinnedStackListener listener) {
         if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS,
                 "registerPinnedStackListener()")) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 37597fb..e452c4a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1128,7 +1128,6 @@
                 }
             }
         } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-            dc.getDockedDividerController().positionDockedStackedDivider(windowFrames.mFrame);
             windowFrames.mContentFrame.set(windowFrames.mFrame);
             if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
                 mMovedByResize = true;
@@ -1937,13 +1936,9 @@
         // animating... let's do something.
         final int left = mWindowFrames.mFrame.left;
         final int top = mWindowFrames.mFrame.top;
-        final Task task = getTask();
-        final boolean adjustedForMinimizedDockOrIme = task != null
-                && (task.getStack().isAdjustedForMinimizedDockedStack()
-                || task.getStack().isAdjustedForIme());
         if (mToken.okToAnimate()
                 && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
-                && !isDragResizing() && !adjustedForMinimizedDockOrIme
+                && !isDragResizing()
                 && getWindowConfiguration().hasMovementAnimations()
                 && !mWinAnimator.mLastHidden
                 && !mSeamlesslyRotated) {
@@ -2250,15 +2245,15 @@
         }
 
         final ActivityStack stack = getRootTask();
-        if (stack != null && stack.shouldIgnoreInput()) {
+        if (stack != null && !stack.isFocusable()) {
             // Ignore when the stack shouldn't receive input event.
             // (i.e. the minimized stack in split screen mode.)
             return false;
         }
 
-        if (PixelFormat.formatHasAlpha(mAttrs.format)) {
-            // Support legacy use cases where transparent windows can still be ime target with
-            // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
+        if (PixelFormat.formatHasAlpha(mAttrs.format) && mAttrs.alpha == 0) {
+            // Support legacy use cases where completely transparent windows can still be ime target
+            // with FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
             // Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to
             // manually synchronize app content to IME animation b/144619551.
             // TODO(b/145812508): remove this once new focus management is complete b/141738570
@@ -2412,13 +2407,6 @@
         }
     }
 
-    void applyAdjustForImeIfNeeded() {
-        final Task task = getTask();
-        if (task != null && task.getStack() != null && task.getStack().isAdjustedForIme()) {
-            task.getStack().applyAdjustForImeIfNeeded(task);
-        }
-    }
-
     @Override
     void switchUser(int userId) {
         super.switchUser(userId);
@@ -4308,10 +4296,6 @@
             }
         }
 
-        if (mAttrs.type == TYPE_INPUT_METHOD) {
-            getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
-        }
-
         return true;
     }
 
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index 35d245f..3e4c992 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -26,6 +26,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.LocusId;
+import android.os.FileUtils;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 
@@ -251,5 +252,6 @@
     void onDestroy() {
         mEventStore.onDestroy();
         mConversationStore.onDestroy();
+        FileUtils.deleteContentsAndDir(mPackageDataDir);
     }
 }
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
index d2f86ee..602e4e1 100644
--- a/services/robotests/Android.bp
+++ b/services/robotests/Android.bp
@@ -26,6 +26,8 @@
         "services.core",
         "services.net",
     ],
+
+    libs: ["ike-stubs"],
 }
 
 //##################################################################
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
index ef0ca66..5160eae 100644
--- a/services/robotests/backup/Android.bp
+++ b/services/robotests/backup/Android.bp
@@ -28,6 +28,8 @@
         "services.core",
         "services.net",
     ],
+
+    libs: ["ike-stubs"],
 }
 
 //##################################################################
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index feae1e1..08bd1ee 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -144,4 +144,49 @@
         Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
         Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
     }
+
+    @Test
+    public void testBrightnessHasLowerPriorityThanUser() {
+        assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
+        assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
+
+        int displayId = 0;
+        DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+        SparseArray<Vote> votes = new SparseArray<>();
+        SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+        votesByDisplay.put(displayId, votes);
+        votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
+        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+        director.injectVotesByDisplay(votesByDisplay);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+        Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+
+        votes.clear();
+        votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
+        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+        director.injectVotesByDisplay(votesByDisplay);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+        Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+
+
+        votes.clear();
+        votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
+        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+        director.injectVotesByDisplay(votesByDisplay);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+        Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+
+        votes.clear();
+        votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
+        votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+        director.injectVotesByDisplay(votesByDisplay);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+        Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+
+
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index 30ab9cd..dc30add 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -117,7 +117,7 @@
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
-        mBatterySaverPolicy.setAccessibilityEnabledForTest(true);
+        mBatterySaverPolicy.setAccessibilityEnabled(true);
         testServiceDefaultValue_Off(ServiceType.VIBRATION);
     }
 
@@ -339,4 +339,57 @@
                 Policy.fromSettings(BATTERY_SAVER_CONSTANTS, ""));
         verifyBatterySaverConstantsUpdated();
     }
+
+    public void testCarModeChanges_Full() {
+        mBatterySaverPolicy.updateConstantsLocked(
+                "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+                        + ",enable_night_mode=true", "");
+        mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
+        assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+
+        mBatterySaverPolicy.setCarModeEnabled(true);
+
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE,
+                        PowerManager.LOCATION_MODE_FOREGROUND_ONLY);
+        assertFalse(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+
+        mBatterySaverPolicy.setCarModeEnabled(false);
+
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
+        assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+    }
+
+    public void testCarModeChanges_Adaptive() {
+        mBatterySaverPolicy.setAdaptivePolicyLocked(
+                Policy.fromSettings(
+                        "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+                                + ",enable_night_mode=true", ""));
+        mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_ADAPTIVE);
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
+        assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+
+        mBatterySaverPolicy.setCarModeEnabled(true);
+
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE,
+                        PowerManager.LOCATION_MODE_FOREGROUND_ONLY);
+        assertFalse(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+
+        mBatterySaverPolicy.setCarModeEnabled(false);
+
+        assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
+                .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
+        assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NIGHT_MODE).batterySaverEnabled);
+    }
 }
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index dab0a5f..767857b 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -23,7 +23,6 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
-    <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java
index 1629ef0..6e7df05 100644
--- a/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java
+++ b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java
@@ -17,7 +17,7 @@
 package com.android.internal.logging;
 
 /**
- * A fake implementation of InstanceIdSequence that returns 0, 1, 2, ...
+ * A fake implementation of InstanceIdSequence that returns 1, 2, ...
  */
 public class InstanceIdSequenceFake extends InstanceIdSequence {
 
@@ -25,13 +25,13 @@
         super(instanceIdMax);
     }
 
-    private int mNextId = 0;
+    private int mNextId = 1;
 
     @Override
     public InstanceId newInstanceId() {
         synchronized (this) {
             if (mNextId >= mInstanceIdMax) {
-                mNextId = 0;
+                mNextId = 1;
             }
             return newInstanceIdInternal(mNextId++);
         }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index d0283f7..b6cdbfb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -153,7 +153,6 @@
 import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
 
-import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.logging.InstanceIdSequenceFake;
@@ -360,7 +359,7 @@
     @Before
     public void setUp() throws Exception {
         // Shell permisssions will override permissions of our app, so add all necessary permissions
-        // fo this test here:
+        // for this test here:
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
                 "android.permission.WRITE_DEVICE_CONFIG",
                 "android.permission.READ_DEVICE_CONFIG",
@@ -1164,7 +1163,7 @@
         assertEquals(PKG, call.r.getSbn().getPackageName());
         assertEquals(0, call.r.getSbn().getId());
         assertEquals(tag, call.r.getSbn().getTag());
-        assertEquals(0, call.getInstanceId());  // Fake instance IDs are assigned in order
+        assertEquals(1, call.getInstanceId());  // Fake instance IDs are assigned in order
     }
 
     @Test
@@ -1186,14 +1185,14 @@
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
                 mNotificationRecordLogger.get(0).event);
-        assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
         assertTrue(mNotificationRecordLogger.get(1).shouldLogReported);
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED,
                 mNotificationRecordLogger.get(1).event);
         // Instance ID doesn't change on update of an active notification
-        assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
     }
 
     @Test
@@ -1248,19 +1247,19 @@
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
                 mNotificationRecordLogger.get(0).event);
         assertTrue(mNotificationRecordLogger.get(0).shouldLogReported);
-        assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
         assertEquals(
                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL,
                 mNotificationRecordLogger.get(1).event);
-        assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
 
         assertEquals(
                 NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED,
                 mNotificationRecordLogger.get(2).event);
         assertTrue(mNotificationRecordLogger.get(2).shouldLogReported);
         // New instance ID because notification was canceled before re-post
-        assertEquals(1, mNotificationRecordLogger.get(2).getInstanceId());
+        assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId());
     }
 
     @Test
@@ -3453,6 +3452,7 @@
     @Test
     public void testStats_dismissalSurface() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
         mService.addNotification(r);
 
         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
@@ -3470,7 +3470,7 @@
         assertEquals(
                 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD,
                 mNotificationRecordLogger.get(0).event);
-        assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
     }
 
     @Test
@@ -4344,6 +4344,7 @@
         final NotificationRecord r = generateNotificationRecord(
                 mTestNotificationChannel, 1, null, true);
         r.setTextChanged(true);
+        r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
         mService.addNotification(r);
 
         mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
@@ -4353,7 +4354,7 @@
         assertEquals(1, mNotificationRecordLogger.getCalls().size());
         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN,
                 mNotificationRecordLogger.get(0).event);
-        assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId());
 
         mService.mNotificationDelegate.onNotificationVisibilityChanged(
                 new NotificationVisibility[]{},
@@ -4364,7 +4365,7 @@
         assertEquals(2, mNotificationRecordLogger.getCalls().size());
         assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE,
                 mNotificationRecordLogger.get(1).event);
-        assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId());
+        assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId());
     }
 
     @Test
@@ -6089,7 +6090,9 @@
 
         // Pretend the shortcut exists
         List<ShortcutInfo> shortcutInfos = new ArrayList<>();
-        shortcutInfos.add(mock(ShortcutInfo.class));
+        ShortcutInfo info = mock(ShortcutInfo.class);
+        when(info.isLongLived()).thenReturn(true);
+        shortcutInfos.add(info);
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
 
         // Test: Send the bubble notification
@@ -6116,7 +6119,8 @@
         verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
 
         // We're no longer a bubble
-        Notification notif2 = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
+        Notification notif2 = mService.getNotificationRecord(
+                nr.getSbn().getKey()).getNotification();
         assertFalse(notif2.isBubbleNotification());
     }
 
@@ -6409,11 +6413,6 @@
         convos.add(convo2);
         when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos);
 
-        // only one valid shortcut
-        LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
-                .setPackage(PKG_P)
-                .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED)
-                .setShortcutIds(Arrays.asList(channel1.getConversationId()));
         ShortcutInfo si = mock(ShortcutInfo.class);
         when(si.getShortLabel()).thenReturn("Hello");
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 2d4b5a7..00b9273 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -51,6 +51,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
@@ -203,16 +204,13 @@
         return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
     }
 
-    private StatusBarNotification getMessagingStyleNotification(@Nullable String shortcutId) {
+    private StatusBarNotification getMessagingStyleNotification() {
         final Builder builder = new Builder(mMockContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
 
         Person person = new Person.Builder().setName("Bob").build();
         builder.setStyle(new Notification.MessagingStyle(person));
-        if (shortcutId != null) {
-            builder.setShortcutId(shortcutId);
-        }
 
         Notification n = builder.build();
         return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
@@ -1122,16 +1120,18 @@
 
     @Test
     public void testIsConversation() {
-        StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id");
+        StatusBarNotification sbn = getMessagingStyleNotification();
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setShortcutInfo(mock(ShortcutInfo.class));
 
         assertTrue(record.isConversation());
     }
 
     @Test
-    public void testIsConversation_nullShortcutId() {
-        StatusBarNotification sbn = getMessagingStyleNotification(null);
+    public void testIsConversation_nullShortcut() {
+        StatusBarNotification sbn = getMessagingStyleNotification();
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setShortcutInfo(null);
 
         assertFalse(record.isConversation());
     }
@@ -1140,25 +1140,28 @@
     public void testIsConversation_bypassShortcutFlagEnabled() {
         Settings.Global.putString(mContentResolver,
                 FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
-        StatusBarNotification sbn = getMessagingStyleNotification(null);
+        StatusBarNotification sbn = getMessagingStyleNotification();
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setShortcutInfo(null);
 
         assertTrue(record.isConversation());
     }
 
     @Test
     public void testIsConversation_channelDemoted() {
-        StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id");
+        StatusBarNotification sbn = getMessagingStyleNotification();
         channel.setDemoted(true);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setShortcutInfo(mock(ShortcutInfo.class));
 
         assertFalse(record.isConversation());
     }
 
     @Test
     public void testIsConversation_withAdjustmentOverride() {
-        StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id");
+        StatusBarNotification sbn = getMessagingStyleNotification();
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        record.setShortcutInfo(mock(ShortcutInfo.class));
 
         Bundle bundle = new Bundle();
         bundle.putBoolean(KEY_NOT_CONVERSATION, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 27f72a1..e4d50c0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -55,6 +55,8 @@
 import android.util.AtomicFile;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.logging.InstanceIdSequenceFake;
 import com.android.server.LocalServices;
@@ -65,6 +67,7 @@
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -116,6 +119,10 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        // Shell permisssions will override permissions of our app, so add all necessary permissions
+        // for this test here:
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                "android.permission.READ_CONTACTS");
 
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
@@ -153,6 +160,12 @@
         mService.setPreferencesHelper(mPreferencesHelper);
     }
 
+    @After
+    public void tearDown() {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().dropShellPermissionIdentity();
+    }
+
     @Test
     public void testInit() throws Exception {
         List<String> dialer0 = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 7204a81..e1ce431f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -255,7 +255,7 @@
     }
 
     private void notifyTransitionStarting(ActivityRecord activity) {
-        final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>();
+        final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
         reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
         mActivityMetricsLogger.notifyTransitionStarting(reasons);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 8c2b293..4cb50c7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -103,12 +103,12 @@
         setUpOnDisplay(mDisplayContent);
 
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertEquals(1, mDisplayContent.mChangingApps.size());
+        assertEquals(1, mDisplayContent.mChangingContainers.size());
 
         // Verify we are in a change transition, but without a snapshot.
         // Though, the test will actually have crashed by now if a snapshot is attempted.
-        assertNull(mActivity.getThumbnail());
-        assertTrue(mActivity.isInChangeTransition());
+        assertNull(mTask.mSurfaceFreezer.mSnapshot);
+        assertTrue(mTask.isInChangeTransition());
 
         waitUntilHandlersIdle();
         mActivity.removeImmediately();
@@ -121,14 +121,14 @@
         setUpOnDisplay(mDisplayContent);
 
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertEquals(1, mDisplayContent.mChangingApps.size());
-        assertTrue(mActivity.isInChangeTransition());
+        assertEquals(1, mDisplayContent.mChangingContainers.size());
+        assertTrue(mTask.isInChangeTransition());
 
         // Removing the app-token from the display should clean-up the
         // the change leash.
         mDisplayContent.removeAppToken(mActivity.token);
-        assertEquals(0, mDisplayContent.mChangingApps.size());
-        assertFalse(mActivity.isInChangeTransition());
+        assertEquals(0, mDisplayContent.mChangingContainers.size());
+        assertFalse(mTask.isInChangeTransition());
 
         waitUntilHandlersIdle();
         mActivity.removeImmediately();
@@ -152,8 +152,8 @@
         assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
 
         // Make sure we're not waiting for a change animation (no leash)
-        assertFalse(mActivity.isInChangeTransition());
-        assertNull(mActivity.getThumbnail());
+        assertFalse(mTask.isInChangeTransition());
+        assertNull(mActivity.mSurfaceFreezer.mSnapshot);
 
         waitUntilHandlersIdle();
         mActivity.removeImmediately();
@@ -165,13 +165,13 @@
         setUpOnDisplay(mDisplayContent);
 
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertEquals(1, mDisplayContent.mChangingApps.size());
-        assertTrue(mActivity.isInChangeTransition());
+        assertEquals(1, mDisplayContent.mChangingContainers.size());
+        assertTrue(mTask.isInChangeTransition());
 
         // Changing visibility should cancel the change transition and become closing
         mActivity.setVisibility(false, false);
-        assertEquals(0, mDisplayContent.mChangingApps.size());
-        assertFalse(mActivity.isInChangeTransition());
+        assertEquals(0, mDisplayContent.mChangingContainers.size());
+        assertFalse(mTask.isInChangeTransition());
 
         waitUntilHandlersIdle();
         mActivity.removeImmediately();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java
deleted file mode 100644
index 3206208..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-@SmallTest
-@Presubmit
-public class DockedStackDividerControllerTests {
-
-    @Test
-    public void testIsDockSideAllowedDockTop() {
-        // Docked top is always allowed
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-    }
-
-    @Test
-    public void testIsDockSideAllowedDockBottom() {
-        // Cannot dock bottom
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
-    }
-
-    @Test
-    public void testIsDockSideAllowedNavigationBarMovable() {
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
-                NAV_BAR_LEFT, true /* navigationBarCanMove */));
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
-                NAV_BAR_RIGHT, true /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
-                NAV_BAR_RIGHT, true /* navigationBarCanMove */));
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
-                NAV_BAR_LEFT, true /* navigationBarCanMove */));
-    }
-
-    @Test
-    public void testIsDockSideAllowedNavigationBarNotMovable() {
-        // Navigation bar is not movable such as tablets
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-        assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-        assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT,
-                NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index d9c5c4c..9a898fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -978,10 +977,7 @@
                 () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
                         false/* toTop */));
         assertNotRestoreTask(
-                () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId,
-                        SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
-                        false /* toTop */, false /* animate */, null /* initialBounds */,
-                        true /* showRecents */));
+                () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
     }
 
     @Test
@@ -1096,14 +1092,10 @@
         assertSecurityException(expectCallable,
                 () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
         assertSecurityException(expectCallable,
-                () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
-                        SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
+                () -> mService.setTaskWindowingModeSplitScreenPrimary(0, true));
         assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
         assertSecurityException(expectCallable,
                 () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
-        assertSecurityException(expectCallable,
-                () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
-                        new Rect()));
         assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
         assertSecurityException(expectCallable,
                 () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 3a724a1..c7f94ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -247,7 +247,7 @@
     @Test
     public void testChange() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        mDisplayContent.mChangingApps.add(win.mActivityRecord);
+        mDisplayContent.mChangingContainers.add(win.mActivityRecord);
         try {
             final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
                     win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150),
@@ -290,7 +290,7 @@
             verify(mThumbnailFinishedCallback).onAnimationFinished(
                     eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
         } finally {
-            mDisplayContent.mChangingApps.clear();
+            mDisplayContent.mChangingContainers.clear();
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index ec20262..0ef2582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -52,7 +52,6 @@
 import static org.mockito.ArgumentMatchers.refEq;
 
 import android.app.ActivityOptions;
-import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -251,13 +250,12 @@
         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(stack).build();
 
-        // Under split screen primary we should be focusable when not minimized
-        mRootWindowContainer.setDockedStackMinimized(false);
+        // Created stacks are focusable by default.
         assertTrue(stack.isTopActivityFocusable());
         assertTrue(activity.isFocusable());
 
-        // Under split screen primary we should not be focusable when minimized
-        mRootWindowContainer.setDockedStackMinimized(true);
+        // If the stack is made unfocusable, its activities should inherit that.
+        stack.setFocusable(false);
         assertFalse(stack.isTopActivityFocusable());
         assertFalse(activity.isFocusable());
 
@@ -308,33 +306,6 @@
     }
 
     /**
-     * Verify split-screen primary stack & task can resized by
-     * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect.
-     */
-    @Test
-    public void testResizeDockedStackForSplitScreenPrimary() {
-        final Rect configSize = new Rect(0, 0, 1000, 1000);
-        final Rect displayedSize = new Rect(0, 0, 300, 300);
-
-        // Create primary split-screen stack with a task.
-        final ActivityStack primaryStack = new StackBuilder(mRootWindowContainer)
-                .setActivityType(ACTIVITY_TYPE_STANDARD)
-                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
-                .setOnTop(true)
-                .build();
-        final Task task = primaryStack.getTopMostTask();
-
-        // Resize dock stack.
-        mService.resizeDockedStack(displayedSize, configSize, null, null, null);
-
-        // Verify dock stack & its task bounds if is equal as resized result.
-        assertEquals(displayedSize, primaryStack.getDisplayedBounds());
-        assertEquals(displayedSize, primaryStack.getDisplayedBounds());
-        assertEquals(configSize, primaryStack.getBounds());
-        assertEquals(configSize, task.getBounds());
-    }
-
-    /**
      * Verify that home stack would be moved to front when the top activity is Recents.
      */
     @Test
@@ -517,7 +488,7 @@
      */
     @Test
     public void testStartHomeOnAllDisplays() {
-        mockResolveHomeActivity();
+        mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
         mockResolveSecondaryHomeActivity();
 
         // Create secondary displays.
@@ -644,30 +615,26 @@
     }
 
     /**
-     * Tests that secondary home should be selected if default home not set.
+     * Tests that secondary home should be selected if primary home not set.
      */
     @Test
-    public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSet() {
-        final Intent defaultHomeIntent = mService.getHomeIntent();
-        final ActivityInfo aInfoDefault = new ActivityInfo();
-        aInfoDefault.name = ResolverActivity.class.getName();
-        doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
-                refEq(defaultHomeIntent));
+    public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
+        // Setup: primary home not set.
+        final Intent primaryHomeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoPrimary = new ActivityInfo();
+        aInfoPrimary.name = ResolverActivity.class.getName();
+        doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
+                refEq(primaryHomeIntent));
+        // Setup: set secondary home.
+        mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
 
-        final String secondaryHomeComponent = mService.mContext.getResources().getString(
-                com.android.internal.R.string.config_secondaryHomeComponent);
-        final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
-        final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
-        final ActivityInfo aInfoSecondary = new ActivityInfo();
-        aInfoSecondary.name = comp.getClassName();
-        doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
-                refEq(secondaryHomeIntent));
-
-        // Should fallback to secondary home if default home not set.
+        // Run the test.
         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
                 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
-
-        assertEquals(comp.getClassName(), resolvedInfo.first.name);
+        final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+        assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+        assertEquals(aInfoSecondary.applicationInfo.packageName,
+                resolvedInfo.first.applicationInfo.packageName);
     }
 
     /**
@@ -675,103 +642,60 @@
      * config_useSystemProvidedLauncherForSecondary.
      */
     @Test
-    public void testResolveSecondaryHomeActivityForced() throws Exception {
-        Resources resources = mContext.getResources();
-        spyOn(resources);
-        try {
-            // setUp: set secondary launcher and force it.
-            final String defaultSecondaryHome =
-                    "com.android.test/com.android.test.TestDefaultSecondaryHome";
-            final ComponentName secondaryComp = ComponentName.unflattenFromString(
-                    defaultSecondaryHome);
-            doReturn(defaultSecondaryHome).when(resources).getString(
-                    com.android.internal.R.string.config_secondaryHomeComponent);
-            doReturn(true).when(resources).getBoolean(
-                    com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
-            final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
-            assertEquals(secondaryComp, secondaryHomeIntent.getComponent());
-            final ActivityInfo aInfoSecondary = new ActivityInfo();
-            aInfoSecondary.name = secondaryComp.getClassName();
-            aInfoSecondary.applicationInfo = new ApplicationInfo();
-            aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName();
-            doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
-                    refEq(secondaryHomeIntent));
-            final Intent homeIntent = mService.getHomeIntent();
-            final ActivityInfo aInfoDefault = new ActivityInfo();
-            aInfoDefault.name = "fakeHomeActivity";
-            aInfoDefault.applicationInfo = new ApplicationInfo();
-            aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
-            doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
-                    refEq(homeIntent));
-            // Let resolveActivities call to validate both main launcher and second launcher so that
-            // resolveActivities call does not work as enabler for secondary.
-            final List<ResolveInfo> resolutions1 = new ArrayList<>();
-            final ResolveInfo resolveInfo1 = new ResolveInfo();
-            resolveInfo1.activityInfo = new ActivityInfo();
-            resolveInfo1.activityInfo.name = aInfoDefault.name;
-            resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo;
-            resolutions1.add(resolveInfo1);
-            doReturn(resolutions1).when(mRootWindowContainer).resolveActivities(anyInt(),
-                    refEq(homeIntent));
-            final List<ResolveInfo> resolutions2 = new ArrayList<>();
-            final ResolveInfo resolveInfo2 = new ResolveInfo();
-            resolveInfo2.activityInfo = new ActivityInfo();
-            resolveInfo2.activityInfo.name = aInfoSecondary.name;
-            resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo;
-            resolutions2.add(resolveInfo2);
-            doReturn(resolutions2).when(mRootWindowContainer).resolveActivities(anyInt(),
-                    refEq(secondaryHomeIntent));
-            doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
-                    any(), anyInt(), anyBoolean());
-
-            // Run the test
-            final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
-                    .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
-            assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name);
-            assertEquals(secondaryComp.getPackageName(),
-                    resolvedInfo.first.applicationInfo.packageName);
-            assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
-        } finally {
-            // tearDown
-            reset(resources);
-        }
-    }
-
-    /**
-     * Tests that secondary home should be selected if default home not support secondary displays
-     * or there is no matched activity in the same package as selected default home.
-     */
-    @Test
-    public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSupportMultiDisplay() {
-        mockResolveHomeActivity();
-
+    public void testResolveSecondaryHomeActivityForced() {
+        // SetUp: set primary home.
+        mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+        // SetUp: set secondary home and force it.
+        mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
+        final Intent secondaryHomeIntent =
+                mService.getSecondaryHomeIntent(null /* preferredPackage */);
         final List<ResolveInfo> resolutions = new ArrayList<>();
-        doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
-
-        final String secondaryHomeComponent = mService.mContext.getResources().getString(
-                com.android.internal.R.string.config_secondaryHomeComponent);
-        final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
-        final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
-        final ActivityInfo aInfoSecondary = new ActivityInfo();
-        aInfoSecondary.name = comp.getClassName();
-        doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
+        final ResolveInfo resolveInfo = new ResolveInfo();
+        final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+        resolveInfo.activityInfo = aInfoSecondary;
+        resolutions.add(resolveInfo);
+        doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(),
                 refEq(secondaryHomeIntent));
+        doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
+                any(), anyInt(), anyBoolean());
 
-        // Should fallback to secondary home if selected default home not support secondary displays
-        // or there is no matched activity in the same package as selected default home.
+        // Run the test.
         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
                 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
-
-        assertEquals(comp.getClassName(), resolvedInfo.first.name);
+        assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+        assertEquals(aInfoSecondary.applicationInfo.packageName,
+                resolvedInfo.first.applicationInfo.packageName);
     }
 
     /**
-     * Tests that default home activity should be selected if it already support secondary displays.
+     * Tests that secondary home should be selected if primary home not support secondary displays
+     * or there is no matched activity in the same package as selected primary home.
      */
     @Test
-    public void testResolveSecondaryHomeActivityWhenDefaultHomeSupportMultiDisplay() {
-        final ActivityInfo aInfoDefault = mockResolveHomeActivity();
+    public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() {
+        // Setup: there is no matched activity in the same package as selected primary home.
+        mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+        final List<ResolveInfo> resolutions = new ArrayList<>();
+        doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
+        // Setup: set secondary home.
+        mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
 
+        // Run the test.
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+        final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+        assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+        assertEquals(aInfoSecondary.applicationInfo.packageName,
+                resolvedInfo.first.applicationInfo.packageName);
+    }
+    /**
+     * Tests that primary home activity should be selected if it already support secondary displays.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() {
+        // SetUp: set primary home.
+        mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+        // SetUp: put primary home info on 2nd item
         final List<ResolveInfo> resolutions = new ArrayList<>();
         final ResolveInfo infoFake1 = new ResolveInfo();
         infoFake1.activityInfo = new ActivityInfo();
@@ -779,7 +703,8 @@
         infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
         infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
         final ResolveInfo infoFake2 = new ResolveInfo();
-        infoFake2.activityInfo = aInfoDefault;
+        final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */);
+        infoFake2.activityInfo = aInfoPrimary;
         resolutions.add(infoFake1);
         resolutions.add(infoFake2);
         doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
@@ -787,13 +712,12 @@
         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
                 any(), anyInt(), anyBoolean());
 
-        // Use default home activity if it support secondary displays.
+        // Run the test.
         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
                 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
-
-        assertEquals(aInfoDefault.applicationInfo.packageName,
+        assertEquals(aInfoPrimary.name, resolvedInfo.first.name);
+        assertEquals(aInfoPrimary.applicationInfo.packageName,
                 resolvedInfo.first.applicationInfo.packageName);
-        assertEquals(aInfoDefault.name, resolvedInfo.first.name);
     }
 
     /**
@@ -801,8 +725,9 @@
      */
     @Test
     public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
-        mockResolveHomeActivity();
-
+        // SetUp: set primary home.
+        mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+        // Setup: prepare two eligible activity info.
         final List<ResolveInfo> resolutions = new ArrayList<>();
         final ResolveInfo infoFake1 = new ResolveInfo();
         infoFake1.activityInfo = new ActivityInfo();
@@ -821,7 +746,7 @@
         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
                 any(), anyInt(), anyBoolean());
 
-        // Use the first one of matched activities in the same package as selected default home.
+        // Use the first one of matched activities in the same package as selected primary home.
         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
                 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
 
@@ -884,32 +809,48 @@
 
     /**
      * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
-     * info for test cases (the original implementation will resolve from the real package manager).
+     * info for test cases.
+     *
+     * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use
+     *                    secondary home intent.
+     * @param forceSystemProvided Indicate to force using system provided home activity.
      */
-    private ActivityInfo mockResolveHomeActivity() {
-        final Intent homeIntent = mService.getHomeIntent();
-        final ActivityInfo aInfoDefault = new ActivityInfo();
-        aInfoDefault.name = "fakeHomeActivity";
-        aInfoDefault.applicationInfo = new ApplicationInfo();
-        aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
-        doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
-                refEq(homeIntent));
-        return aInfoDefault;
+    private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) {
+        ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
+        Intent targetIntent;
+        if (primaryHome) {
+            targetIntent = mService.getHomeIntent();
+        } else {
+            Resources resources = mContext.getResources();
+            spyOn(resources);
+            doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString(
+                    com.android.internal.R.string.config_secondaryHomePackage);
+            doReturn(forceSystemProvided).when(resources).getBoolean(
+                    com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+            targetIntent = mService.getSecondaryHomeIntent(null /* preferredPackage */);
+        }
+        doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
+                refEq(targetIntent));
     }
 
     /**
      * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
-     * activity info for test cases (the original implementation will resolve from the real package
-     * manager).
+     * activity info for test cases.
      */
     private void mockResolveSecondaryHomeActivity() {
         final Intent secondaryHomeIntent = mService
                 .getSecondaryHomeIntent(null /* preferredPackage */);
-        final ActivityInfo aInfoSecondary = new ActivityInfo();
-        aInfoSecondary.name = "fakeSecondaryHomeActivity";
-        aInfoSecondary.applicationInfo = new ApplicationInfo();
-        aInfoSecondary.applicationInfo.packageName = "fakeSecondaryHomePackage";
+        final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
         doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
                 .resolveSecondaryHomeActivity(anyInt(), anyInt());
     }
+
+    private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) {
+        final ActivityInfo aInfo = new ActivityInfo();
+        aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity";
+        aInfo.applicationInfo = new ApplicationInfo();
+        aInfo.applicationInfo.packageName =
+                primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage";
+        return  aInfo;
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index bd8aacb..20d9aff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -25,6 +25,7 @@
 import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -36,6 +37,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
@@ -138,6 +140,7 @@
         final int orientation = Configuration.ORIENTATION_PORTRAIT;
         final float scaleFraction = 0.25f;
         final Rect contentInsets = new Rect(1, 2, 3, 4);
+        final Point taskSize = new Point(5, 6);
 
         try {
             ActivityManager.TaskSnapshot.Builder builder =
@@ -147,14 +150,13 @@
             builder.setSystemUiVisibility(systemUiVisibility);
             builder.setWindowingMode(windowingMode);
             builder.setColorSpace(sRGB);
-            builder.setIsLowResolution(true);
             builder.setOrientation(orientation);
             builder.setContentInsets(contentInsets);
             builder.setIsTranslucent(true);
-            builder.setScaleFraction(0.25f);
             builder.setSnapshot(buffer);
             builder.setIsRealSnapshot(true);
             builder.setPixelFormat(pixelFormat);
+            builder.setTaskSize(taskSize);
 
             // Not part of TaskSnapshot itself, used in screenshot process
             assertEquals(pixelFormat, builder.getPixelFormat());
@@ -165,13 +167,15 @@
             assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility());
             assertEquals(windowingMode, snapshot.getWindowingMode());
             assertEquals(sRGB, snapshot.getColorSpace());
-            assertTrue(snapshot.isLowResolution());
+            // Snapshots created with the Builder class are always high-res. The only way to get a
+            // low-res snapshot is to load it from the disk in TaskSnapshotLoader.
+            assertFalse(snapshot.isLowResolution());
             assertEquals(orientation, snapshot.getOrientation());
             assertEquals(contentInsets, snapshot.getContentInsets());
             assertTrue(snapshot.isTranslucent());
-            assertEquals(scaleFraction, builder.getScaleFraction(), 0.001f);
             assertSame(buffer, snapshot.getSnapshot());
             assertTrue(snapshot.isRealSnapshot());
+            assertEquals(taskSize, snapshot.getTaskSize());
         } finally {
             if (buffer != null) {
                 buffer.destroy();
@@ -188,11 +192,9 @@
 
         final ActivityManager.TaskSnapshot.Builder builder =
                 new ActivityManager.TaskSnapshot.Builder();
-        final float scaleFraction = 0.8f;
         mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
-                scaleFraction, PixelFormat.UNKNOWN, builder);
+                PixelFormat.UNKNOWN, builder);
 
-        assertEquals(scaleFraction, builder.getScaleFraction(), 0 /* delta */);
         // The pixel format should be selected automatically.
         assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 0b16e5c..40f15b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -19,12 +19,16 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -36,10 +40,12 @@
 
 import androidx.test.filters.MediumTest;
 
+import com.android.server.wm.TaskSnapshotLoader.PreRLegacySnapshotConfig;
 import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
 
 import java.io.File;
 import java.util.function.Predicate;
@@ -55,6 +61,8 @@
 @RunWith(WindowTestRunner.class)
 public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
 
+    private static final float DELTA = 0.00001f;
+
     private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
 
     @Test
@@ -148,29 +156,172 @@
     }
 
     @Test
-    public void testLowResolutionPersistAndLoadSnapshot() {
+    public void testLegacyPLowRamConfig() throws Exception {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(ActivityManager.class)
+                .startMocking();
+
+        when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true);
+
+        // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+        // for any P low_ram device
+        final int taskWidth = 0;
+        final float legacyScale = 0f;
+        final boolean hasHighResFile = false;
+
+        PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+        assertNotNull(highResConf);
+        assertEquals(highResConf.mScale, 0.6f, DELTA);
+        assertTrue(highResConf.mForceLoadReducedJpeg);
+
+        PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+        assertNotNull(lowResConf);
+        assertEquals(lowResConf.mScale, 0.6f, DELTA);
+        assertTrue(lowResConf.mForceLoadReducedJpeg);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testLegacyPNonLowRamConfig() throws Exception {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(ActivityManager.class)
+                .startMocking();
+
+        when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false);
+
+        // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+        // for any O device, or a P non-low_ram device
+        final int taskWidth = 0;
+        final float legacyScale = 0f;
+        final boolean hasHighResFile = true;
+
+        PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+        assertNotNull(highResConf);
+        assertEquals(highResConf.mScale, 1.0f, DELTA);
+        assertFalse(highResConf.mForceLoadReducedJpeg);
+
+        PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+        assertNotNull(lowResConf);
+        assertEquals(lowResConf.mScale, 0.5f, DELTA);
+        assertFalse(lowResConf.mForceLoadReducedJpeg);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testLegacyQLowRamConfig() throws Exception {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(ActivityManager.class)
+                .startMocking();
+
+        when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true);
+
+        // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+        // for any Q low_ram device
+        final int taskWidth = 0;
+        final float legacyScale = 0.6f;
+        final boolean hasHighResFile = false;
+
+        PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+        assertNotNull(highResConf);
+        assertEquals(highResConf.mScale, legacyScale, DELTA);
+        assertEquals(highResConf.mScale, 0.6f, DELTA);
+        assertTrue(highResConf.mForceLoadReducedJpeg);
+
+        PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+        assertNotNull(lowResConf);
+        assertEquals(lowResConf.mScale, legacyScale, DELTA);
+        assertEquals(lowResConf.mScale, 0.6f, DELTA);
+        assertTrue(lowResConf.mForceLoadReducedJpeg);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testLegacyQNonLowRamConfig() throws Exception {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(ActivityManager.class)
+                .startMocking();
+
+        when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false);
+
+        // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+        // for any Q non-low_ram device
+        final int taskWidth = 0;
+        final float legacyScale = 0.8f;
+        final boolean hasHighResFile = true;
+
+        PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+        assertNotNull(highResConf);
+        assertEquals(highResConf.mScale, legacyScale, DELTA);
+        assertEquals(highResConf.mScale, 0.8f, DELTA);
+        assertFalse(highResConf.mForceLoadReducedJpeg);
+
+        PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+        assertNotNull(lowResConf);
+        assertEquals(lowResConf.mScale, 0.5f * legacyScale, DELTA);
+        assertEquals(lowResConf.mScale, 0.5f * 0.8f, DELTA);
+        assertFalse(lowResConf.mForceLoadReducedJpeg);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testNonLegacyRConfig() throws Exception {
+        // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file,
+        // for any R device
+        final int taskWidth = 1440;
+        final float legacyScale = 0f;
+        final boolean hasHighResFile = true;
+
+        PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */);
+        assertNull(highResConf);
+
+        PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig(
+                taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */);
+        assertNull(lowResConf);
+    }
+
+    @Test
+    public void testDisabledLowResolutionPersistAndLoadSnapshot() {
+        mPersister.setEnableLowResSnapshots(false);
+
         TaskSnapshot a = new TaskSnapshotBuilder()
-                .setScale(0.5f)
+                .setScaleFraction(0.5f)
                 .setIsLowResolution(true)
                 .build();
         assertTrue(a.isLowResolution());
         mPersister.persistSnapshot(1, mTestUserId, a);
         mPersister.waitForQueueEmpty();
         final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
-                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
+                new File(FILES_DIR.getPath() + "/snapshots/1.jpg")};
         final File[] nonExistsFiles = new File[]{
-                new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+                new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
         };
         assertTrueForFiles(files, File::exists, " must exist");
         assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
-        final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, true /* isLowResolution */);
+        final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */);
         assertNotNull(snapshot);
         assertEquals(TEST_INSETS, snapshot.getContentInsets());
         assertNotNull(snapshot.getSnapshot());
         assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
 
         final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId,
-                false /* isLowResolution */);
+                true /* isLowResolution */);
         assertNull(snapshotNotExist);
     }
 
@@ -271,13 +422,11 @@
     @Test
     public void testScalePersistAndLoadSnapshot() {
         TaskSnapshot a = new TaskSnapshotBuilder()
-                .setScale(0.25f)
+                .setScaleFraction(0.25f)
                 .build();
         TaskSnapshot b = new TaskSnapshotBuilder()
-                .setScale(0.75f)
+                .setScaleFraction(0.75f)
                 .build();
-        assertEquals(0.25f, a.getScale(), 1E-5);
-        assertEquals(0.75f, b.getScale(), 1E-5);
         mPersister.persistSnapshot(1, mTestUserId, a);
         mPersister.persistSnapshot(2, mTestUserId, b);
         mPersister.waitForQueueEmpty();
@@ -287,8 +436,6 @@
                 false /* isLowResolution */);
         assertNotNull(snapshotA);
         assertNotNull(snapshotB);
-        assertEquals(0.25f, snapshotA.getScale(), 1E-5);
-        assertEquals(0.75f, snapshotB.getScale(), 1E-5);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 4612dba..fa6663c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -30,6 +30,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.UserManager;
 import android.view.Surface;
@@ -87,8 +88,10 @@
      * Builds a TaskSnapshot.
      */
     static class TaskSnapshotBuilder {
+        private static final int SNAPSHOT_WIDTH = 100;
+        private static final int SNAPSHOT_HEIGHT = 100;
 
-        private float mScale = 1f;
+        private float mScaleFraction = 1f;
         private boolean mIsLowResolution = false;
         private boolean mIsRealSnapshot = true;
         private boolean mIsTranslucent = false;
@@ -96,8 +99,11 @@
         private int mSystemUiVisibility = 0;
         private int mRotation = Surface.ROTATION_0;
 
-        TaskSnapshotBuilder setScale(float scale) {
-            mScale = scale;
+        TaskSnapshotBuilder() {
+        }
+
+        TaskSnapshotBuilder setScaleFraction(float scale) {
+            mScaleFraction = scale;
             return this;
         }
 
@@ -132,15 +138,20 @@
         }
 
         TaskSnapshot build() {
-            final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
+            // To satisfy existing tests, ensure the graphics buffer is always 100x100, and
+            // compute the ize of the task according to mScaleFraction.
+            Point taskSize = new Point((int) (SNAPSHOT_WIDTH / mScaleFraction),
+                    (int) (SNAPSHOT_HEIGHT / mScaleFraction));
+            final GraphicBuffer buffer = GraphicBuffer.create(SNAPSHOT_WIDTH, SNAPSHOT_HEIGHT,
+                    PixelFormat.RGBA_8888,
                     USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
             Canvas c = buffer.lockCanvas();
             c.drawColor(Color.RED);
             buffer.unlockCanvasAndPost(c);
             return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer,
                     ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
-                    mRotation, TEST_INSETS,
-                    mIsLowResolution, mScale, mIsRealSnapshot,
+                    mRotation, taskSize, TEST_INSETS,
+                    mIsLowResolution, mIsRealSnapshot,
                     mWindowingMode, mSystemUiVisibility, mIsTranslucent);
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index bb0e5ae..2164de9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -38,6 +38,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
@@ -67,12 +68,22 @@
             int windowFlags, Rect taskBounds) {
         final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
                 GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER);
+
+        // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+        // this behavior set the taskSize to be the same as the taskBounds width and height. The
+        // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+        // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+        // taskBounds
+        assertEquals(width, taskBounds.width());
+        assertEquals(height, taskBounds.height());
+        Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
         final TaskSnapshot snapshot = new TaskSnapshot(
                 System.currentTimeMillis(),
                 new ComponentName("", ""), buffer,
                 ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
-                Surface.ROTATION_0, contentInsets, false,
-                1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+                Surface.ROTATION_0, taskSize, contentInsets, false,
+                true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
                 0 /* systemUiVisibility */, false /* isTranslucent */);
         mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
                 createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
@@ -152,7 +163,7 @@
 
     @Test
     public void testCalculateSnapshotCrop_taskNotOnTop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100));
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
         assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 2c68cc7..85e4a16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,9 +251,11 @@
 
         // b/145812508: special legacy use-case for transparent/translucent windows.
         appWindow.mAttrs.format = PixelFormat.TRANSPARENT;
+        appWindow.mAttrs.alpha = 0;
         assertTrue(appWindow.canBeImeTarget());
 
         appWindow.mAttrs.format = PixelFormat.OPAQUE;
+        appWindow.mAttrs.alpha = 1;
         appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
         assertFalse(appWindow.canBeImeTarget());
         appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
@@ -276,8 +278,7 @@
         spyOn(appWindow);
         spyOn(controller);
         spyOn(stack);
-        doReturn(true).when(controller).isMinimizedDock();
-        doReturn(true).when(controller).isHomeStackResizable();
+        stack.setFocusable(false);
         doReturn(stack).when(appWindow).getRootTask();
 
         // Make sure canBeImeTarget is false due to shouldIgnoreInput is true;
@@ -619,9 +620,10 @@
     }
 
     @Test
-    public void testCantReceiveTouchWhenShouldIgnoreInput() {
+    public void testCantReceiveTouchWhenNotFocusable() {
         final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
-        win0.mActivityRecord.getStack().setAdjustedForMinimizedDock(1 /* Any non 0 value works */);
+        win0.mActivityRecord.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        win0.mActivityRecord.getStack().setFocusable(false);
         assertTrue(win0.cantReceiveTouchInput());
     }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 07cc2d4..8e85bb2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1917,7 +1917,19 @@
                     return;
                 }
                 try {
-                    // Adbd will be started by AdbService once Global.ADB_ENABLED is set.
+                    if ((config & UsbManager.FUNCTION_ADB) != 0) {
+                        /**
+                         * Start adbd if ADB function is included in the configuration.
+                         */
+                        LocalServices.getService(AdbManagerInternal.class)
+                                .startAdbdForTransport(AdbTransportType.USB);
+                    } else {
+                        /**
+                         * Stop adbd otherwise
+                         */
+                        LocalServices.getService(AdbManagerInternal.class)
+                                .stopAdbdForTransport(AdbTransportType.USB);
+                    }
                     UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
                             config, chargingFunctions);
                     mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,
diff --git a/startop/scripts/app_startup/parse_metrics b/startop/scripts/app_startup/parse_metrics
index 036609f..3fa1462 100755
--- a/startop/scripts/app_startup/parse_metrics
+++ b/startop/scripts/app_startup/parse_metrics
@@ -42,12 +42,14 @@
     -h, --help                  usage information (this)
     -v, --verbose               enable extra verbose printing
     -t, --timeout <sec>         how many seconds to timeout when trying to wait for logcat to change
+    -rfd, --reportfullydrawn    wait for report fully drawn (default: off)
 EOF
 }
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 source "$DIR/lib/common"
 
+report_fully_drawn="n"
 package=""
 activity=""
 timeout=5
@@ -81,6 +83,11 @@
       -s|--simulate)
         simulate="y"
         ;;
+      -rfd|--reportfullydrawn)
+        report_fully_drawn="y"
+        ;;
+
+
       *)
         echo "Invalid argument: $1" >&2
         exit 1
@@ -190,12 +197,15 @@
 
 parse_metric_from_logcat "Displayed_ms" "$pattern" "$re_pattern"
 
-# 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms
-pattern="ActivityTaskManager: Fully drawn ${package}"
-#re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*'
-re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*'
+# Only track ReportFullyDrawn with --reportfullydrawn/-rfd flags
+if [[ $report_fully_drawn == y ]]; then
+  # 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms
+  pattern="ActivityTaskManager: Fully drawn ${package}"
+  #re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*'
+  re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*'
 
-parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern"
+  parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern"
+fi
 
 # also call into package-specific scripts if there are additional metrics
 if [[ -x "$DIR/metrics/$package" ]]; then
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
index 92a31c3..31f6253 100755
--- a/startop/scripts/app_startup/run_app_with_prefetch
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -35,6 +35,7 @@
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 source "$DIR/../iorap/common"
 
+report_fully_drawn="n"
 needs_trace_file="n"
 input_file=""
 package=""
@@ -70,6 +71,10 @@
         mode="$2"
         shift
         ;;
+      -rfd|--reportfullydrawn)
+        report_fully_drawn="y"
+        shift
+        ;;
       -c|--count)
         count="$2"
         ((count+=1))
@@ -403,7 +408,11 @@
   join_by ',' "${all_metrics[@]}"
 }
 
-metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate | parse_metrics_header)"
+if [[ $report_fully_drawn == y ]]; then
+  metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate --reportfullydrawn | parse_metrics_header)"
+else
+  metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate | parse_metrics_header)"
+fi
 
 # TODO: This loop logic could probably be moved into app_startup_runner.py
 for ((i=0;i<count;++i)) do
@@ -411,6 +420,9 @@
   verbose_print "====         ITERATION $i             ===="
   verbose_print "=========================================="
   if [[ $mode != "warm" ]]; then
+    # The package must be killed **before** we drop caches, otherwise pages will stay resident.
+    verbose_print "Kill package for non-warm start."
+    remote_pkill "$package"
     verbose_print "Drop caches for non-warm start."
     # Drop all caches to get cold starts.
     adb shell "echo 3 > /proc/sys/vm/drop_caches"
@@ -423,7 +435,12 @@
   pre_launch_timestamp="$(logcat_save_timestamp)"
 
   # TODO: multiple metrics output.
+
+if [[ $report_fully_drawn == y ]]; then
+  total_time="$(timeout $timeout "$DIR/launch_application" "$package" "$activity" | "$DIR/parse_metrics" --package "$package" --activity "$activity" --timestamp "$pre_launch_timestamp" --reportfullydrawn | parse_metrics_output)"
+else
   total_time="$(timeout $timeout "$DIR/launch_application" "$package" "$activity" | "$DIR/parse_metrics" --package "$package" --activity "$activity" --timestamp "$pre_launch_timestamp" | parse_metrics_output)"
+fi
 
   if [[ $? -ne 0 ]]; then
     echo "WARNING: Skip bad result, try iteration again." >&2
diff --git a/startop/scripts/app_startup/run_app_with_prefetch.py b/startop/scripts/app_startup/run_app_with_prefetch.py
old mode 100644
new mode 100755
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9d77623..6a40487 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4096,7 +4096,8 @@
         /** Prefix of all Wifi.KEY_* constants. */
         public static final String KEY_PREFIX = "wifi.";
         /**
-        * It contains the maximum client count definition that the carrier owns.
+        * It contains the maximum client count definition that the carrier sets.
+        * The default is 0, which means that the carrier hasn't set a requirement.
         */
         public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT =
                 KEY_PREFIX + "hotspot_maximum_client_count";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0660776..31d9654 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2788,39 +2788,22 @@
     /**
      * Returns the ISO-3166 country code equivalent of the MCC (Mobile Country Code) of the current
      * registered operator or the cell nearby, if available.
-     * <p>
-     * The ISO-3166 country code is provided in lowercase 2 character format.
-     * <p>
-     * Note: In multi-sim, this returns a shared emergency network country iso from other
-     * subscription if the subscription used to create the TelephonyManager doesn't camp on
-     * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding
-     * slot.
+     *
      * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine
      * if on a CDMA network).
      * <p>
      * @return the lowercase 2 character ISO-3166 country code, or empty string if not available.
      */
     public String getNetworkCountryIso() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony == null) return "";
-            return telephony.getNetworkCountryIsoForPhone(getPhoneId(),
-                    null /* no permission check */, null);
-        } catch (RemoteException ex) {
-            return "";
-        }
+        return getNetworkCountryIso(getSlotIndex());
     }
 
     /**
      * Returns the ISO-3166 country code equivalent of the MCC (Mobile Country Code) of the current
-     * registered operator or the cell nearby, if available.
-     * <p>
-     * The ISO-3166 country code is provided in lowercase 2 character format.
-     * <p>
-     * Note: In multi-sim, this returns a shared emergency network country iso from other
-     * subscription if the subscription used to create the TelephonyManager doesn't camp on
-     * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding
-     * slot.
+     * registered operator or the cell nearby, if available. This is same as
+     * {@link #getNetworkCountryIso()} but allowing specifying the SIM slot index. This is used for
+     * accessing network country info from the SIM slot that does not have SIM inserted.
+     *
      * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine
      * if on a CDMA network).
      * <p>
@@ -2831,22 +2814,18 @@
      *
      * @throws IllegalArgumentException when the slotIndex is invalid.
      *
-     * {@hide}
      */
-    @SystemApi
-    @TestApi
     @NonNull
-    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getNetworkCountryIso(int slotIndex) {
         try {
-            if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
+            if (slotIndex != SubscriptionManager.DEFAULT_SIM_SLOT_INDEX
+                    && !SubscriptionManager.isValidSlotIndex(slotIndex)) {
                 throw new IllegalArgumentException("invalid slot index " + slotIndex);
             }
 
             ITelephony telephony = getITelephony();
             if (telephony == null) return "";
-            return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName(),
-                    getFeatureId());
+            return telephony.getNetworkCountryIsoForPhone(slotIndex);
         } catch (RemoteException ex) {
             return "";
         }
@@ -11092,7 +11071,6 @@
      * @param enabled True if enabling the data, otherwise disabling.
      * @hide
      */
-    @SystemApi
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setPolicyDataEnabled(boolean enabled) {
         try {
@@ -11195,7 +11173,6 @@
      * @param isEnabled {@code true} for enabling; {@code false} for disabling.
      * @hide
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setAlwaysReportSignalStrength(boolean isEnabled) {
         try {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 861925f..af5089f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -281,7 +281,7 @@
      * operator's MCC (Mobile Country Code).
      * @see android.telephony.TelephonyManager#getNetworkCountryIso
      */
-    String getNetworkCountryIsoForPhone(int phoneId, String callingPkg, String callingFeatureId);
+    String getNetworkCountryIsoForPhone(int phoneId);
 
     /**
      * Returns the neighboring cell information of the device.
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 1c8b6be..61f3dba 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -30,6 +30,7 @@
     private ITestDevice mTestDevice;
     private static final String SYSTEM_SERVER_PROFILE =
             "/data/misc/profiles/cur/0/android/primary.prof";
+    private static final boolean USE_PHENOTYPE = false;
 
     @Override
     public void setDevice(ITestDevice testDevice) {
@@ -41,16 +42,33 @@
         return mTestDevice;
     }
 
+    private String getProperty(String property) throws Exception {
+        if (USE_PHENOTYPE) {
+            return mTestDevice.getProperty("persist.device_config.runtime_native_boot."
+                    + property);
+        } else {
+            return mTestDevice.executeShellCommand("getprop dalvik.vm." + property).trim();
+        }
+    }
+
+    private String setProperty(String property, String value) throws Exception {
+        if (USE_PHENOTYPE) {
+            return mTestDevice.executeShellCommand(
+                "device_config put runtime_native_boot " + property + " " + value);
+        } else {
+            return mTestDevice.executeShellCommand(
+                "setprop dalvik.vm." + property + " " + value);
+        }
+    }
+
     /**
      * Validate that the boot image profile properties are set.
      */
     public void validateProperties() throws Exception {
-        String res = mTestDevice.getProperty(
-                "persist.device_config.runtime_native_boot.profilebootclasspath");
-        assertTrue("profile boot class path not enabled", res != null && res.equals("true"));
-        res = mTestDevice.getProperty(
-                "persist.device_config.runtime_native_boot.profilesystemserver");
-        assertTrue("profile system server not enabled", res != null && res.equals("true"));
+        String res = getProperty("profilebootclasspath");
+        assertTrue("profile boot class path not enabled: " + res, "true".equals(res));
+        res = getProperty("profilesystemserver");
+        assertTrue("profile system server not enabled: " + res, "true".equals(res));
     }
 
     private boolean forceSaveProfile(String pkg) throws Exception {
@@ -67,33 +85,48 @@
     @Test
     public void testSystemServerProfile() throws Exception {
         final int numIterations = 20;
+        String res;
+        // Set properties and wait for them to be readable.
         for (int i = 1; i <= numIterations; ++i) {
-            String res;
-            res = mTestDevice.getProperty(
-                    "persist.device_config.runtime_native_boot.profilebootclasspath");
-            boolean profileBootClassPath = res != null && res.equals("true");
-            res = mTestDevice.getProperty(
-                    "persist.device_config.runtime_native_boot.profilesystemserver");
-            boolean profileSystemServer = res != null && res.equals("true");
+            String pbcp = getProperty("profilebootclasspath");
+            boolean profileBootClassPath = "true".equals(pbcp);
+            String pss = getProperty("profilesystemserver");
+            boolean profileSystemServer = "true".equals(pss);
             if (profileBootClassPath && profileSystemServer) {
                 break;
             }
             if (i == numIterations) {
-                assertTrue("profile system server not enabled", profileSystemServer);
-                assertTrue("profile boot class path not enabled", profileSystemServer);
+                assertTrue("profile system server not enabled: " + pss, profileSystemServer);
+                assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
             }
 
-            res = mTestDevice.executeShellCommand(
-                    "device_config put runtime_native_boot profilebootclasspath true");
-            res = mTestDevice.executeShellCommand(
-                    "device_config put runtime_native_boot profilesystemserver true");
-            res = mTestDevice.executeShellCommand("stop");
-            res = mTestDevice.executeShellCommand("start");
-            Thread.sleep(5000);
+            setProperty("profilebootclasspath", "true");
+            setProperty("profilesystemserver", "true");
+            Thread.sleep(1000);
         }
+
+        // Restart shell and wait for system boot.
+        res = mTestDevice.executeShellCommand("stop");
+        assertTrue("stop shell: " + res, res.length() == 0);
+        res = mTestDevice.executeShellCommand("start");
+        assertTrue("start shell: " + res, res.length() == 0);
+        for (int i = 1; i <= numIterations; ++i) {
+            String pbcp = getProperty("profilebootclasspath");
+            boolean profileBootClassPath = "true".equals(pbcp);
+            String pss = getProperty("profilesystemserver");
+            boolean profileSystemServer = "true".equals(pss);
+            if (profileBootClassPath && profileSystemServer) {
+                break;
+            }
+            if (i == numIterations) {
+                assertTrue("profile system server not enabled: " + pss, profileSystemServer);
+                assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
+            }
+            Thread.sleep(1000);
+        }
+
         // Trunacte the profile before force it to be saved to prevent previous profiles
         // causing the test to pass.
-        String res;
         res = mTestDevice.executeShellCommand("truncate -s 0 " + SYSTEM_SERVER_PROFILE).trim();
         assertTrue(res, res.length() == 0);
         // Wait up to 20 seconds for the profile to be saved.
diff --git a/wifi/Android.bp b/wifi/Android.bp
index e253d6d..91174d3 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -47,7 +47,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/WifiOemMigrationHook.java",
+        "java/android/net/wifi/WifiMigration.java",
         "java/android/net/wifi/nl80211/*.java",
         ":libwificond_ipc_aidl",
     ],
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
index 462a978..d691f41 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
@@ -16,16 +16,14 @@
 
 package android.net.wifi;
 
-import android.net.NetworkScore;
-
 /**
- * Interface for Wi-Fi network score callback.
+ * Interface for Wi-Fi score callback.
  *
  * @hide
  */
 oneway interface IScoreChangeCallback
 {
-    void onScoreChange(int sessionId, in NetworkScore score);
+    void onScoreChange(int sessionId, int score);
 
     void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
 }
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 51927af..9256c57 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -24,8 +24,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
@@ -861,19 +859,7 @@
         }
     }
 
-    /**
-     * Construct an empty scan result.
-     *
-     * Test code has a need to construct a ScanResult in a specific state.
-     * (Note that mocking using Mockito does not work if the object needs to be parceled and
-     * unparceled.)
-     * Export a @SystemApi default constructor to allow tests to construct an empty ScanResult
-     * object. The test can then directly set the fields it cares about.
-     *
-     * @hide
-     */
-    @SystemApi
-    @VisibleForTesting
+    /** Construct an empty scan result. */
     public ScanResult() {
     }
 
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 0c306b4..142854a 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -28,8 +28,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -380,20 +378,7 @@
         }
     }
 
-    /**
-     * WifiInfo exports an immutable public API.
-     * However, test code has a need to construct a WifiInfo in a specific state.
-     * (Note that mocking using Mockito does not work if the object needs to be parceled and
-     * unparceled.)
-     * Export a @SystemApi Builder to allow tests to construct a WifiInfo object
-     * in the desired state, without sacrificing WifiInfo's immutability.
-     *
-     * @hide
-     */
-    // This builder was not made public to reduce confusion for external developers as there are
-    // no legitimate uses for this builder except for testing.
-    @SystemApi
-    @VisibleForTesting
+    /** Builder for WifiInfo */
     public static final class Builder {
         private final WifiInfo mWifiInfo = new WifiInfo();
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b1a4cac..dece855 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -39,7 +39,6 @@
 import android.net.DhcpInfo;
 import android.net.MacAddress;
 import android.net.Network;
-import android.net.NetworkScore;
 import android.net.NetworkStack;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
@@ -5994,11 +5993,10 @@
          *
          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
          *                  {@link WifiConnectedNetworkScorer#start(int)}.
-         * @param score The {@link android.net.NetworkScore} object representing the
-         *              characteristics of current Wi-Fi network. Populated by connected network
-         *              scorer in applications.
+         * @param score The score representing link quality of current Wi-Fi network connection.
+         *              Populated by connected network scorer in applications..
          */
-        void onScoreChange(int sessionId, @NonNull NetworkScore score);
+        void onScoreChange(int sessionId, int score);
 
         /**
          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -6024,7 +6022,7 @@
         }
 
         @Override
-        public void onScoreChange(int sessionId, @NonNull NetworkScore score) {
+        public void onScoreChange(int sessionId, int score) {
             try {
                 mScoreChangeCallback.onScoreChange(sessionId, score);
             } catch (RemoteException e) {
diff --git a/wifi/java/android/net/wifi/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiMigration.java
similarity index 93%
rename from wifi/java/android/net/wifi/WifiOemMigrationHook.java
rename to wifi/java/android/net/wifi/WifiMigration.java
index 5301dd0..a3482d7 100755
--- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java
+++ b/wifi/java/android/net/wifi/WifiMigration.java
@@ -34,9 +34,9 @@
  * @hide
  */
 @SystemApi
-public final class WifiOemMigrationHook {
+public final class WifiMigration {
 
-    private WifiOemMigrationHook() { }
+    private WifiMigration() { }
 
     /**
      * Container for all the wifi config data to migrate.
@@ -161,16 +161,16 @@
      * Load data from OEM's config store.
      * <p>
      * Note:
-     * <li> OEM's need to implement {@link #loadFromConfigStore()} ()} 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>OEMs need to implement {@link #loadFromConfigStore()} ()} only if their
+     * existing config store format or file locations differs from the vanilla AOSP implementation.
      * </li>
-     * <li> The wifi mainline module will invoke {@link #loadFromConfigStore()} method on every
+     * <li>The wifi mainline module will invoke {@link #loadFromConfigStore()} 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 #loadFromConfigStore()} occurs when a previously released
-     * device upgrades to the wifi mainline module from an OEM implementation of the wifi stack.
+     * their config store files when {@link #removeConfigStore()} is invoked.
+     * <li>The first & only relevant invocation of {@link #loadFromConfigStore()} occurs when a
+     * previously released device upgrades to the wifi mainline module from an OEM implementation
+     * of the wifi stack.
      * </li>
      *
      * @return Instance of {@link ConfigStoreMigrationData} for migrating data, null if no
@@ -178,11 +178,27 @@
      */
     @Nullable
     public static ConfigStoreMigrationData loadFromConfigStore() {
-        // Note: OEM's should add code to parse data from their config store format here!
+        // Note: OEMs should add code to parse data from their config store format here!
         return null;
     }
 
     /**
+     * Remove OEM's config store.
+     * <p>
+     * Note:
+     * <li>OEMs need to implement {@link #removeConfigStore()} 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 #removeConfigStore()} after it migrates
+     * all the existing data retrieved from {@link #loadFromConfigStore()}.
+     * </li>
+     */
+    public static void removeConfigStore() {
+        // Note: OEMs should remove their custom config store files here!
+    }
+
+    /**
      * Container for all the wifi settings data to migrate.
      */
     public static final class SettingsMigrationData implements Parcelable {
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index a854a4b..6dbb0bd 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -753,7 +753,7 @@
                                  boolean isUserInteractionRequired,
                                  boolean isUserAllowedToManuallyConnect,
                                  boolean isInitialAutoJoinEnabled,
-            boolean isNetworkUntrusted) {
+                                 boolean isNetworkUntrusted) {
         checkNotNull(networkConfiguration);
         this.wifiConfiguration = networkConfiguration;
         this.passpointConfiguration = passpointConfiguration;
@@ -858,13 +858,106 @@
     }
 
     /**
+     * Get the BSSID, or null if unset.
+     * @see Builder#setBssid(MacAddress)
+     */
+    @Nullable
+    public MacAddress getBssid() {
+        if (wifiConfiguration.BSSID == null) {
+            return null;
+        }
+        return MacAddress.fromString(wifiConfiguration.BSSID);
+    }
+
+    /** @see Builder#setCredentialSharedWithUser(boolean) */
+    public boolean isCredentialSharedWithUser() {
+        return isUserAllowedToManuallyConnect;
+    }
+
+    /** @see Builder#setIsAppInteractionRequired(boolean) */
+    public boolean isAppInteractionRequired() {
+        return isAppInteractionRequired;
+    }
+
+    /** @see Builder#setIsEnhancedOpen(boolean)  */
+    public boolean isEnhancedOpen() {
+        return wifiConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE);
+    }
+
+    /** @see Builder#setIsHiddenSsid(boolean)  */
+    public boolean isHiddenSsid() {
+        return wifiConfiguration.hiddenSSID;
+    }
+
+    /** @see Builder#setIsInitialAutojoinEnabled(boolean)  */
+    public boolean isInitialAutojoinEnabled() {
+        return isInitialAutoJoinEnabled;
+    }
+
+    /** @see Builder#setIsMetered(boolean)  */
+    public boolean isMetered() {
+        return wifiConfiguration.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED;
+    }
+
+    /** @see Builder#setIsUserInteractionRequired(boolean)  */
+    public boolean isUserInteractionRequired() {
+        return isUserInteractionRequired;
+    }
+
+    /**
      * Get the {@link PasspointConfiguration} associated with this Suggestion, or null if this
      * Suggestion is not for a Passpoint network.
-     * @hide
      */
-    @SystemApi
     @Nullable
-    public PasspointConfiguration getPasspointConfiguration() {
+    public PasspointConfiguration getPasspointConfig() {
         return passpointConfiguration;
     }
+
+    /** @see Builder#setPriority(int)  */
+    @IntRange(from = 0)
+    public int getPriority() {
+        return wifiConfiguration.priority;
+    }
+
+    /**
+     * Return the SSID of the network, or null if this is a Passpoint network.
+     * @see Builder#setSsid(String)
+     */
+    @Nullable
+    public String getSsid() {
+        if (wifiConfiguration.SSID == null) {
+            return null;
+        }
+        return WifiInfo.sanitizeSsid(wifiConfiguration.SSID);
+    }
+
+    /** @see Builder#setUntrusted(boolean)  */
+    public boolean isUntrusted() {
+        return isNetworkUntrusted;
+    }
+
+    /**
+     * Get the WifiEnterpriseConfig, or null if unset.
+     * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig)
+     * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)
+     * @see Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)
+     */
+    @Nullable
+    public WifiEnterpriseConfig getEnterpriseConfig() {
+        return wifiConfiguration.enterpriseConfig;
+    }
+
+    /**
+     * Get the passphrase, or null if unset.
+     * @see Builder#setWapiPassphrase(String)
+     * @see Builder#setWpa2Passphrase(String)
+     * @see Builder#setWpa3Passphrase(String)
+     */
+    @Nullable
+    public String getPassphrase() {
+        if (wifiConfiguration.preSharedKey == null) {
+            return null;
+        }
+        return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
+    }
 }