Merge "Fix 'history' text" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 4a1f96e..5e068ee 100644
--- a/Android.bp
+++ b/Android.bp
@@ -481,6 +481,7 @@
         "framework-platform-compat-config",
         "libcore-platform-compat-config",
         "services-platform-compat-config",
+        "documents-ui-compat-config",
     ],
     static_libs: [
         // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
diff --git a/apex/Android.bp b/apex/Android.bp
index 362cf95..051986e 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,12 +31,12 @@
 
 priv_apps = " " +
     "--show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
+        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
     "\\) "
 
 module_libs = " " +
     " --show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
+        "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
     "\\) "
 
 stubs_defaults {
@@ -48,6 +48,7 @@
 stubs_defaults {
     name: "framework-module-stubs-defaults-systemapi",
     args: mainline_stubs_args + priv_apps,
+    srcs: [":framework-annotations"],
     installable: false,
 }
 
@@ -59,11 +60,13 @@
 stubs_defaults {
     name: "framework-module-api-defaults-module_libs_api",
     args: mainline_stubs_args + module_libs,
+    srcs: [":framework-annotations"],
     installable: false,
 }
 
 stubs_defaults {
     name: "framework-module-stubs-defaults-module_libs_api",
     args: mainline_stubs_args + module_libs + priv_apps,
+    srcs: [":framework-annotations"],
     installable: false,
 }
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 4c98b5f..62c90dfa 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -54,7 +54,8 @@
      *
      * @hide
      */
-    public static final int REASON_RESTRAINED = JobProtoEnums.STOP_REASON_RESTRAINED; // 6.
+    public static final int REASON_RESTRICTED_BUCKET =
+            JobProtoEnums.STOP_REASON_RESTRICTED_BUCKET; // 6.
 
     /**
      * All the stop reason codes. This should be regarded as an immutable array at runtime.
@@ -72,7 +73,7 @@
             REASON_TIMEOUT,
             REASON_DEVICE_IDLE,
             REASON_DEVICE_THERMAL,
-            REASON_RESTRAINED,
+            REASON_RESTRICTED_BUCKET,
     };
 
     /**
@@ -88,7 +89,7 @@
             case REASON_TIMEOUT: return "timeout";
             case REASON_DEVICE_IDLE: return "device_idle";
             case REASON_DEVICE_THERMAL: return "thermal";
-            case REASON_RESTRAINED: return "restrained";
+            case REASON_RESTRICTED_BUCKET: return "restricted_bucket";
             default: return "unknown:" + reasonCode;
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index c1e529f..b86aba6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1074,7 +1074,15 @@
                     uId, null, jobStatus.getBatteryName(),
                     FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
                     JobProtoEnums.STOP_REASON_CANCELLED, jobStatus.getStandbyBucket(),
-                    jobStatus.getJobId());
+                    jobStatus.getJobId(),
+                    jobStatus.hasChargingConstraint(),
+                    jobStatus.hasBatteryNotLowConstraint(),
+                    jobStatus.hasStorageNotLowConstraint(),
+                    jobStatus.hasTimingDelayConstraint(),
+                    jobStatus.hasDeadlineConstraint(),
+                    jobStatus.hasIdleConstraint(),
+                    jobStatus.hasConnectivityConstraint(),
+                    jobStatus.hasContentTriggerConstraint());
 
             // If the job is immediately ready to run, then we can just immediately
             // put it in the pending list and try to schedule it.  This is especially
@@ -1955,9 +1963,19 @@
                 continue;
             }
             if (!running.isReady()) {
-                serviceContext.cancelExecutingJobLocked(
-                        JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
-                        "cancelled due to unsatisfied constraints");
+                // If a restricted job doesn't have dynamic constraints satisfied, assume that's
+                // the reason the job is being stopped, instead of because of other constraints
+                // not being satisfied.
+                if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
+                        && !running.areDynamicConstraintsSatisfied()) {
+                    serviceContext.cancelExecutingJobLocked(
+                            JobParameters.REASON_RESTRICTED_BUCKET,
+                            "cancelled due to restricted bucket");
+                } else {
+                    serviceContext.cancelExecutingJobLocked(
+                            JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
+                            "cancelled due to unsatisfied constraints");
+                }
             } else {
                 final JobRestriction restriction = checkIfRestricted(running);
                 if (restriction != null) {
@@ -3015,6 +3033,10 @@
         return 0;
     }
 
+    void resetExecutionQuota(@NonNull String pkgName, int userId) {
+        mQuotaController.clearAppStats(pkgName, userId);
+    }
+
     void resetScheduleQuota() {
         mQuotaTracker.clear();
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index 6becf04..9571708 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -66,6 +66,8 @@
                     return getJobState(pw);
                 case "heartbeat":
                     return doHeartbeat(pw);
+                case "reset-execution-quota":
+                    return resetExecutionQuota(pw);
                 case "reset-schedule-quota":
                     return resetScheduleQuota(pw);
                 case "trigger-dock-state":
@@ -346,6 +348,40 @@
         return -1;
     }
 
+    private int resetExecutionQuota(PrintWriter pw) throws Exception {
+        checkPermission("reset execution quota");
+
+        int userId = UserHandle.USER_SYSTEM;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-u":
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+
+                default:
+                    pw.println("Error: unknown option '" + opt + "'");
+                    return -1;
+            }
+        }
+
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        final String pkgName = getNextArgRequired();
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mInternal.resetExecutionQuota(pkgName, userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return 0;
+    }
+
     private int resetScheduleQuota(PrintWriter pw) throws Exception {
         checkPermission("reset schedule quota");
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 26db4a3..565ed95 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -22,6 +22,7 @@
 import android.app.job.IJobService;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
+import android.app.job.JobProtoEnums;
 import android.app.job.JobWorkItem;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
@@ -45,6 +46,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.job.controllers.JobStatus;
@@ -273,9 +275,20 @@
                 return false;
             }
             mJobPackageTracker.noteActive(job);
+            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                    job.getSourceUid(), null, job.getBatteryName(),
+                    FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED,
+                    JobProtoEnums.STOP_REASON_UNKNOWN, job.getStandbyBucket(), job.getJobId(),
+                    job.hasChargingConstraint(),
+                    job.hasBatteryNotLowConstraint(),
+                    job.hasStorageNotLowConstraint(),
+                    job.hasTimingDelayConstraint(),
+                    job.hasDeadlineConstraint(),
+                    job.hasIdleConstraint(),
+                    job.hasConnectivityConstraint(),
+                    job.hasContentTriggerConstraint());
             try {
-                mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid(),
-                        job.getStandbyBucket(), job.getJobId());
+                mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
             } catch (RemoteException e) {
                 // Whatever.
             }
@@ -779,10 +792,21 @@
         applyStoppedReasonLocked(reason);
         completedJob = mRunningJob;
         mJobPackageTracker.noteInactive(completedJob, mParams.getStopReason(), reason);
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                completedJob.getSourceUid(), null, completedJob.getBatteryName(),
+                FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
+                mParams.getStopReason(), completedJob.getStandbyBucket(), completedJob.getJobId(),
+                completedJob.hasChargingConstraint(),
+                completedJob.hasBatteryNotLowConstraint(),
+                completedJob.hasStorageNotLowConstraint(),
+                completedJob.hasTimingDelayConstraint(),
+                completedJob.hasDeadlineConstraint(),
+                completedJob.hasIdleConstraint(),
+                completedJob.hasConnectivityConstraint(),
+                completedJob.hasContentTriggerConstraint());
         try {
-            mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
-                    mRunningJob.getSourceUid(), mParams.getStopReason(),
-                    mRunningJob.getStandbyBucket(), mRunningJob.getJobId());
+            mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
+                    mParams.getStopReason());
         } catch (RemoteException e) {
             // Whatever.
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index aa3d74a..d7b1e07 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.job.controllers;
 
+import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
+
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
@@ -196,6 +198,9 @@
         } else {
             isActive = (activeState == KNOWN_ACTIVE);
         }
+        if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) {
+            Slog.wtf(TAG, "App became active but still in NEVER bucket");
+        }
         boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
         didChange |= jobStatus.setUidActive(isActive);
         return didChange;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index b63cc19..81dbc87 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1271,7 +1271,8 @@
         // sessions (exempt from dynamic restrictions), we need the additional check to ensure
         // that NEVER jobs don't run.
         // TODO: cleanup quota and standby bucket management so we don't need the additional checks
-        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) {
+        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied)
+                || getEffectiveStandbyBucket() == NEVER_INDEX) {
             return false;
         }
         // Deadline constraint trumps other constraints besides quota and dynamic (except for
@@ -1293,6 +1294,11 @@
             CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW
                     | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
 
+    /** Returns true whenever all dynamically set constraints are satisfied. */
+    public boolean areDynamicConstraintsSatisfied() {
+        return mReadyDynamicSatisfied;
+    }
+
     /**
      * @return Whether the constraints set on this job are satisfied.
      */
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 8eefac8..4393a95 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -579,23 +579,7 @@
             Slog.wtf(TAG, "Told app removed but given null package name.");
             return;
         }
-        final int userId = UserHandle.getUserId(uid);
-        mTrackedJobs.delete(userId, packageName);
-        Timer timer = mPkgTimers.get(userId, packageName);
-        if (timer != null) {
-            if (timer.isActive()) {
-                Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off.");
-                timer.dropEverythingLocked();
-            }
-            mPkgTimers.delete(userId, packageName);
-        }
-        mTimingSessions.delete(userId, packageName);
-        QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
-        if (alarmListener != null) {
-            mAlarmManager.cancel(alarmListener);
-            mInQuotaAlarmListeners.delete(userId, packageName);
-        }
-        mExecutionStatsCache.delete(userId, packageName);
+        clearAppStats(packageName, UserHandle.getUserId(uid));
         mForegroundUids.delete(uid);
         mUidToPackageCache.remove(uid);
     }
@@ -610,6 +594,26 @@
         mUidToPackageCache.clear();
     }
 
+    /** Drop all historical stats and stop tracking any active sessions for the specified app. */
+    public void clearAppStats(@NonNull String packageName, int userId) {
+        mTrackedJobs.delete(userId, packageName);
+        Timer timer = mPkgTimers.get(userId, packageName);
+        if (timer != null) {
+            if (timer.isActive()) {
+                Slog.e(TAG, "clearAppStats called before Timer turned off.");
+                timer.dropEverythingLocked();
+            }
+            mPkgTimers.delete(userId, packageName);
+        }
+        mTimingSessions.delete(userId, packageName);
+        QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+        if (alarmListener != null) {
+            mAlarmManager.cancel(alarmListener);
+            mInQuotaAlarmListeners.delete(userId, packageName);
+        }
+        mExecutionStatsCache.delete(userId, packageName);
+    }
+
     private boolean isUidInForeground(int uid) {
         if (UserHandle.isCore(uid)) {
             return true;
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 2f3e2ac..4c96263 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -63,11 +63,7 @@
     shared_libs: [
         "libnativehelper", // Has stable abi - should not be copied into apex.
         "liblog",  // Has a stable abi - should not be copied into apex.
-    ],
-    static_libs: [
-        //TODO: make shared - need libstatssocket to also live in the apex.
         "libstatssocket",
-        "libcutils", // TODO: remove - needed by libstatssocket
     ],
     //TODO: is libc++_static correct?
     stl: "libc++_static",
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 a2f2c06..2ec3bcc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2992,9 +2992,7 @@
     method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public String getSettingsActivityName();
-    method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.Context);
     method public String loadDescription(android.content.pm.PackageManager);
-    method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager);
     method public CharSequence loadSummary(android.content.pm.PackageManager);
     method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
     method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int);
@@ -31106,6 +31104,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();
@@ -31377,6 +31376,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>);
@@ -31560,6 +31568,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;
   }
@@ -56956,6 +56978,7 @@
     method @NonNull public android.view.inline.InlinePresentationSpec getPresentationSpec();
     method @NonNull public String getSource();
     method @NonNull public String getType();
+    method public boolean isPinned();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionInfo> CREATOR;
     field public static final String SOURCE_AUTOFILL = "android:autofill";
diff --git a/api/system-current.txt b/api/system-current.txt
index 3b95f32..9a1aacd 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
@@ -7314,8 +7315,8 @@
     method @Deprecated public int getDisableReasonCounter(int);
     method @Deprecated public long getDisableTime();
     method @Deprecated public static int getMaxNetworkSelectionDisableReason();
-    method @Deprecated @Nullable public static String getNetworkDisableReasonString(int);
     method @Deprecated public int getNetworkSelectionDisableReason();
+    method @Deprecated @Nullable public static String getNetworkSelectionDisableReasonString(int);
     method @Deprecated public int getNetworkSelectionStatus();
     method @Deprecated @NonNull public String getNetworkStatusString();
     method @Deprecated public boolean hasEverConnected();
@@ -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);
@@ -9939,6 +9931,7 @@
     method @NonNull public android.service.autofill.augmented.FillResponse build();
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
   }
 
@@ -9966,28 +9959,6 @@
     method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
   }
 
-  public abstract class CarrierMessagingServiceWrapper {
-    ctor public CarrierMessagingServiceWrapper();
-    method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String);
-    method public void disposeConnection(@NonNull android.content.Context);
-    method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-    method public void filterSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-    method public abstract void onServiceReady();
-    method public void sendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-    method public void sendMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-    method public void sendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-    method public void sendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
-  }
-
-  public abstract static class CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper {
-    ctor public CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper();
-    method public void onDownloadMmsComplete(int);
-    method public void onFilterComplete(int);
-    method public void onSendMmsComplete(int, @Nullable byte[]);
-    method public void onSendMultipartSmsComplete(int, @Nullable int[]);
-    method public void onSendSmsComplete(int, int);
-  }
-
 }
 
 package android.service.contentcapture {
@@ -11795,7 +11766,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);
@@ -11810,7 +11780,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);
@@ -11939,45 +11908,6 @@
     field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0
   }
 
-  public class TelephonyRegistryManager {
-    method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
-    method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
-    method public void listenForSubscriber(int, @NonNull String, @NonNull String, @NonNull android.telephony.PhoneStateListener, int, boolean);
-    method public void notifyActiveDataSubIdChanged(int);
-    method public void notifyBarringInfoChanged(int, int, @NonNull android.telephony.BarringInfo);
-    method public void notifyCallForwardingChanged(int, boolean);
-    method public void notifyCallQualityChanged(int, int, @NonNull android.telephony.CallQuality, int);
-    method public void notifyCallStateChanged(int, int, int, @Nullable String);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyCallStateChangedForAllSubscriptions(int, @Nullable String);
-    method public void notifyCarrierNetworkChange(boolean);
-    method public void notifyCellInfoChanged(int, @NonNull java.util.List<android.telephony.CellInfo>);
-    method public void notifyCellLocation(int, @NonNull android.telephony.CellIdentity);
-    method public void notifyDataActivationStateChanged(int, int, int);
-    method public void notifyDataActivityChanged(int, int);
-    method public void notifyDataConnectionForSubscriber(int, int, int, @Nullable android.telephony.PreciseDataConnectionState);
-    method public void notifyDisconnectCause(int, int, int, int);
-    method public void notifyDisplayInfoChanged(int, int, @NonNull android.telephony.DisplayInfo);
-    method public void notifyEmergencyNumberList(int, int);
-    method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo);
-    method public void notifyMessageWaitingChanged(int, int, boolean);
-    method public void notifyOpportunisticSubscriptionInfoChanged();
-    method public void notifyOutgoingEmergencyCall(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
-    method public void notifyOutgoingEmergencySms(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
-    method public void notifyPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
-    method public void notifyPreciseCallState(int, int, int, int, int);
-    method public void notifyPreciseDataConnectionFailed(int, int, int, @Nullable String, int);
-    method public void notifyRadioPowerStateChanged(int, int, int);
-    method public void notifyRegistrationFailed(int, int, @NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
-    method public void notifyServiceStateChanged(int, int, @NonNull android.telephony.ServiceState);
-    method public void notifySignalStrengthChanged(int, int, @NonNull android.telephony.SignalStrength);
-    method public void notifySrvccStateChanged(int, int);
-    method public void notifySubscriptionInfoChanged();
-    method public void notifyUserMobileDataStateChanged(int, int, boolean);
-    method public void notifyVoiceActivationStateChanged(int, int, int);
-    method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
-    method public void removeOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
-  }
-
   public final class UiccAccessRule implements android.os.Parcelable {
     ctor public UiccAccessRule(byte[], @Nullable String, long);
     method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 0f8694f..f25f108 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3270,6 +3270,7 @@
     method @NonNull public android.service.autofill.augmented.FillResponse build();
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
   }
 
@@ -5211,7 +5212,7 @@
   }
 
   public final class InlineSuggestionInfo implements android.os.Parcelable {
-    method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.view.inline.InlinePresentationSpec, @NonNull String, @Nullable String[]);
+    method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.view.inline.InlinePresentationSpec, @NonNull String, @Nullable String[], @NonNull String, boolean);
   }
 
   public final class InlineSuggestionsResponse implements android.os.Parcelable {
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 66f5c39..645dc93 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -36,18 +36,7 @@
     ],
     host_supported: true,
     srcs: [
-        "libidmap2/BinaryStreamVisitor.cpp",
-        "libidmap2/CommandLineOptions.cpp",
-        "libidmap2/FileUtils.cpp",
-        "libidmap2/Idmap.cpp",
-        "libidmap2/Policies.cpp",
-        "libidmap2/PrettyPrintVisitor.cpp",
-        "libidmap2/RawPrintVisitor.cpp",
-        "libidmap2/ResourceMapping.cpp",
-        "libidmap2/ResourceUtils.cpp",
-        "libidmap2/Result.cpp",
-        "libidmap2/XmlParser.cpp",
-        "libidmap2/ZipFile.cpp",
+        "libidmap2/**/*.cpp",
     ],
     export_include_dirs: ["include"],
     target: {
@@ -61,6 +50,7 @@
                 "libcutils",
                 "libutils",
                 "libziparchive",
+                "libidmap2_policies",
             ],
         },
         host: {
@@ -73,6 +63,37 @@
                 "libcutils",
                 "libutils",
                 "libziparchive",
+                "libidmap2_policies",
+            ],
+        },
+    },
+}
+
+cc_library {
+    name: "libidmap2_policies",
+    defaults: [
+        "idmap2_defaults",
+    ],
+    host_supported: true,
+    export_include_dirs: ["libidmap2_policies/include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+        android: {
+            static: {
+                enabled: false,
+            },
+            shared_libs: [
+                "libandroidfw",
+            ],
+        },
+        host: {
+            shared: {
+                enabled: false,
+            },
+            static_libs: [
+                "libandroidfw",
             ],
         },
     },
@@ -118,6 +139,7 @@
                 "libutils",
                 "libz",
                 "libziparchive",
+                "libidmap2_policies",
             ],
         },
         host: {
@@ -129,6 +151,7 @@
                 "liblog",
                 "libutils",
                 "libziparchive",
+                "libidmap2_policies",
             ],
             shared_libs: [
                 "libz",
@@ -162,6 +185,7 @@
                 "libidmap2",
                 "libutils",
                 "libziparchive",
+                "libidmap2_policies",
             ],
         },
         host: {
@@ -173,12 +197,14 @@
                 "liblog",
                 "libutils",
                 "libziparchive",
+                "libidmap2_policies",
             ],
             shared_libs: [
                 "libz",
             ],
         },
     },
+
 }
 
 cc_binary {
@@ -199,6 +225,7 @@
         "libidmap2",
         "libutils",
         "libziparchive",
+        "libidmap2_policies",
     ],
     static_libs: [
         "libidmap2daidl",
@@ -231,3 +258,16 @@
     ],
     path: "idmap2d/aidl",
 }
+
+aidl_interface {
+    name: "overlayable_policy_aidl",
+    srcs: [":overlayable_policy_aidl_files"],
+}
+
+filegroup {
+    name: "overlayable_policy_aidl_files",
+    srcs: [
+        "idmap2d/aidl/android/os/OverlayablePolicy.aidl",
+    ],
+    path: "idmap2d/aidl",
+}
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index 3ff6d35..9682b6e 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -20,15 +20,14 @@
 #include <fstream>
 #include <memory>
 #include <ostream>
-#include <sstream>
-#include <string>
 #include <vector>
 
+#include "androidfw/ResourceTypes.h"
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
-#include "idmap2/Policies.h"
+#include "idmap2/PolicyUtils.h"
 #include "idmap2/SysTrace.h"
 
 using android::ApkAssets;
@@ -36,14 +35,15 @@
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::Idmap;
-using android::idmap2::PoliciesToBitmask;
-using android::idmap2::PolicyBitmask;
-using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
 using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::PoliciesToBitmaskResult;
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 Result<Unit> Create(const std::vector<std::string>& args) {
   SYSTRACE << "Create " << args;
   std::string target_apk_path;
@@ -78,7 +78,7 @@
   }
 
   PolicyBitmask fulfilled_policies = 0;
-  auto conv_result = PoliciesToBitmask(policies);
+  auto conv_result = PoliciesToBitmaskResult(policies);
   if (conv_result) {
     fulfilled_policies |= *conv_result;
   } else {
@@ -86,7 +86,7 @@
   }
 
   if (fulfilled_policies == 0) {
-    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+    fulfilled_policies |= PolicyFlags::PUBLIC;
   }
 
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 0b0541f..ba4ca62 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -20,8 +20,6 @@
 #include <fstream>
 #include <memory>
 #include <ostream>
-#include <sstream>
-#include <string>
 #include <vector>
 
 #include "android-base/stringprintf.h"
@@ -30,7 +28,9 @@
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/Policies.h"
+#include "idmap2/PolicyUtils.h"
 #include "idmap2/SysTrace.h"
+#include "Commands.h"
 
 using android::ApkAssets;
 using android::base::StringPrintf;
@@ -38,13 +38,11 @@
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::Idmap;
-using android::idmap2::PoliciesToBitmask;
-using android::idmap2::PolicyBitmask;
-using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
 using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::PoliciesToBitmaskResult;
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
 Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
@@ -80,7 +78,7 @@
   }
 
   PolicyBitmask fulfilled_policies = 0;
-  auto conv_result = PoliciesToBitmask(policies);
+  auto conv_result = PoliciesToBitmaskResult(policies);
   if (conv_result) {
     fulfilled_policies |= *conv_result;
   } else {
@@ -88,7 +86,7 @@
   }
 
   if (fulfilled_policies == 0) {
-    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+    fulfilled_policies |= PolicyFlags::PUBLIC;
   }
 
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
@@ -105,32 +103,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/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index b4fdd0b..da04532 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -20,7 +20,6 @@
 #include <memory>
 #include <ostream>
 #include <set>
-#include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
@@ -34,25 +33,24 @@
 #include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 #include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
 
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Error;
 using android::idmap2::Idmap;
-using android::idmap2::kPolicyOdm;
-using android::idmap2::kPolicyOem;
-using android::idmap2::kPolicyProduct;
-using android::idmap2::kPolicyPublic;
-using android::idmap2::kPolicySystem;
-using android::idmap2::kPolicyVendor;
-using android::idmap2::PolicyBitmask;
-using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
 using android::idmap2::Unit;
+using android::idmap2::policy::kPolicyOdm;
+using android::idmap2::policy::kPolicyOem;
+using android::idmap2::policy::kPolicyProduct;
+using android::idmap2::policy::kPolicyPublic;
+using android::idmap2::policy::kPolicySystem;
+using android::idmap2::policy::kPolicyVendor;
 using android::idmap2::utils::ExtractOverlayManifestInfo;
 using android::idmap2::utils::FindFiles;
 using android::idmap2::utils::OverlayManifestInfo;
 
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+
 namespace {
 
 struct InputOverlay {
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 4aabf83..f84e4b5 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -33,7 +33,6 @@
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
-#include "idmap2/Policies.h"
 #include "idmap2/SysTrace.h"
 #include "utils/String8.h"
 
@@ -42,11 +41,12 @@
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
-using android::idmap2::PolicyBitmask;
 using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+
 namespace {
 
 Status ok() {
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index cd474c0..f4cf651 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,14 +20,6 @@
  * @hide
  */
 interface IIdmap2 {
-  const int POLICY_PUBLIC = 0x00000001;
-  const int POLICY_SYSTEM_PARTITION = 0x00000002;
-  const int POLICY_VENDOR_PARTITION = 0x00000004;
-  const int POLICY_PRODUCT_PARTITION = 0x00000008;
-  const int POLICY_SIGNATURE = 0x00000010;
-  const int POLICY_ODM_PARTITION = 0x00000020;
-  const int POLICY_OEM_PARTITION = 0x00000040;
-
   @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
   boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
   boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
new file mode 100644
index 0000000..02b27a8
--- /dev/null
+++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @see ResourcesTypes.h ResTable_overlayable_policy_header::PolicyFlags
+ * @hide
+ */
+interface OverlayablePolicy {
+  const int PUBLIC = 0x00000001;
+  const int SYSTEM_PARTITION = 0x00000002;
+  const int VENDOR_PARTITION = 0x00000004;
+  const int PRODUCT_PARTITION = 0x00000008;
+  const int SIGNATURE = 0x00000010;
+  const int ODM_PARTITION = 0x00000020;
+  const int OEM_PARTITION = 0x00000040;
+  const int ACTOR_SIGNATURE = 0x00000080;
+}
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index d4a0c322..2e4836e 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -73,7 +73,6 @@
 #include "androidfw/ApkAssets.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
-#include "idmap2/Policies.h"
 #include "idmap2/ResourceMapping.h"
 
 namespace android::idmap2 {
diff --git a/cmds/idmap2/include/idmap2/PolicyUtils.h b/cmds/idmap2/include/idmap2/PolicyUtils.h
new file mode 100644
index 0000000..b95b8b4
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/PolicyUtils.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_
+#define IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+
+namespace android::idmap2::utils {
+
+// Returns a Result object containing a policy flag bitmask built from a list of policy strings.
+// On error will contain a human readable message listing the invalid policies.
+Result<PolicyBitmask> PoliciesToBitmaskResult(const std::vector<std::string>& policies);
+
+// Converts a bitmask of policy flags into a list of their string representation as would be written
+// into XML
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask);
+
+}  // namespace android::idmap2::utils
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index 86dfab2..5869409 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -30,6 +30,8 @@
 
 using android::idmap2::utils::OverlayManifestInfo;
 
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+
 namespace android::idmap2 {
 
 struct TargetValue {
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
deleted file mode 100644
index 495fe61..0000000
--- a/cmds/idmap2/libidmap2/Policies.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "idmap2/Policies.h"
-
-#include <iterator>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "androidfw/ResourceTypes.h"
-#include "idmap2/Idmap.h"
-#include "idmap2/Result.h"
-
-namespace android::idmap2 {
-
-Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies) {
-  static const std::unordered_map<android::StringPiece, PolicyFlags> kStringToFlag = {
-      {kPolicyOdm, PolicyFlags::POLICY_ODM_PARTITION},
-      {kPolicyOem, PolicyFlags::POLICY_OEM_PARTITION},
-      {kPolicyPublic, PolicyFlags::POLICY_PUBLIC},
-      {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION},
-      {kPolicySignature, PolicyFlags::POLICY_SIGNATURE},
-      {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION},
-      {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION},
-  };
-
-  PolicyBitmask bitmask = 0;
-  for (const std::string& policy : policies) {
-    const auto iter = kStringToFlag.find(policy);
-    if (iter != kStringToFlag.end()) {
-      bitmask |= iter->second;
-    } else {
-      return Error("unknown policy \"%s\"", policy.c_str());
-    }
-  }
-
-  return Result<PolicyBitmask>(bitmask);
-}
-
-std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
-  std::vector<std::string> policies;
-
-  if ((bitmask & PolicyFlags::POLICY_ODM_PARTITION) != 0) {
-    policies.emplace_back(kPolicyOdm);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_OEM_PARTITION) != 0) {
-    policies.emplace_back(kPolicyOem);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_PUBLIC) != 0) {
-    policies.emplace_back(kPolicyPublic);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_PRODUCT_PARTITION) != 0) {
-    policies.emplace_back(kPolicyProduct);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) {
-    policies.emplace_back(kPolicySignature);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_SYSTEM_PARTITION) != 0) {
-    policies.emplace_back(kPolicySystem);
-  }
-
-  if ((bitmask & PolicyFlags::POLICY_VENDOR_PARTITION) != 0) {
-    policies.emplace_back(kPolicyVendor);
-  }
-
-  return policies;
-}
-
-}  // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/PolicyUtils.cpp b/cmds/idmap2/libidmap2/PolicyUtils.cpp
new file mode 100644
index 0000000..fc5182a
--- /dev/null
+++ b/cmds/idmap2/libidmap2/PolicyUtils.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/idmap2/PolicyUtils.h"
+
+#include <sstream>
+
+#include "android-base/strings.h"
+#include "idmap2/Policies.h"
+
+using android::idmap2::policy::kPolicyStringToFlag;
+
+namespace android::idmap2::utils {
+
+Result<PolicyBitmask> PoliciesToBitmaskResult(const std::vector<std::string>& policies) {
+  std::vector<std::string> unknown_policies;
+  PolicyBitmask bitmask = 0;
+  for (const std::string& policy : policies) {
+    const auto result = std::find_if(kPolicyStringToFlag.begin(), kPolicyStringToFlag.end(),
+                                     [policy](const auto& it) { return policy == it.first; });
+    if (result != kPolicyStringToFlag.end()) {
+      bitmask |= result->second;
+    } else {
+      unknown_policies.emplace_back(policy.empty() ? "empty" : policy);
+    }
+  }
+
+  if (unknown_policies.empty()) {
+    return Result<PolicyBitmask>(bitmask);
+  }
+
+  auto prefix = unknown_policies.size() == 1 ? "policy" : "policies";
+  return Error("unknown %s: \"%s\"", prefix, android::base::Join(unknown_policies, ",").c_str());
+}
+
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
+  std::vector<std::string> policies;
+
+  for (const auto& policy : kPolicyStringToFlag) {
+    if ((bitmask & policy.second) != 0) {
+      policies.emplace_back(policy.first.to_string());
+    }
+  }
+
+  return policies;
+}
+
+}  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 43cfec3..f82c8f1 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -24,11 +24,16 @@
 #include <vector>
 
 #include "android-base/stringprintf.h"
+#include "androidfw/ResourceTypes.h"
+#include "idmap2/PolicyUtils.h"
 #include "idmap2/ResourceUtils.h"
 
 using android::base::StringPrintf;
+using android::idmap2::utils::BitmaskToPolicies;
 using android::idmap2::utils::IsReference;
 using android::idmap2::utils::ResToTypeEntryName;
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
@@ -55,9 +60,8 @@
                               const PolicyBitmask& fulfilled_policies,
                               const ResourceId& target_resource) {
   static constexpr const PolicyBitmask sDefaultPolicies =
-      PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
-      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
-      PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
+      PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
+      PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
 
   // If the resource does not have an overlayable definition, allow the resource to be overlaid if
   // the overlay is preinstalled or signed with the same signature as the target.
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
similarity index 60%
rename from cmds/idmap2/include/idmap2/Policies.h
rename to cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index 87edd35..4973b76 100644
--- a/cmds/idmap2/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -14,18 +14,22 @@
  * limitations under the License.
  */
 
-#include <string>
-#include <vector>
-
-#include "Result.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
 #ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
 #define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
 
-namespace android::idmap2 {
+#include <array>
+#include <string>
+#include <vector>
 
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
+namespace android::idmap2::policy {
+
+constexpr const char* kPolicyActor = "actor";
 constexpr const char* kPolicyOdm = "odm";
 constexpr const char* kPolicyOem = "oem";
 constexpr const char* kPolicyProduct = "product";
@@ -34,15 +38,16 @@
 constexpr const char* kPolicySystem = "system";
 constexpr const char* kPolicyVendor = "vendor";
 
-using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
-using PolicyBitmask = uint32_t;
-
-// Parses the string representations of policies into a bitmask.
-Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies);
-
-// Retrieves the string representations of policies in the bitmask.
-std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask);
-
-}  // namespace android::idmap2
+inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = {
+    std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE},
+    {kPolicyOdm, PolicyFlags::ODM_PARTITION},
+    {kPolicyOem, PolicyFlags::OEM_PARTITION},
+    {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION},
+    {kPolicyPublic, PolicyFlags::PUBLIC},
+    {kPolicySignature, PolicyFlags::SIGNATURE},
+    {kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
+    {kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
+};
+}  // namespace android::idmap2::policy
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index b535f30..d896cf9 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -34,6 +34,7 @@
 #include <string>
 #include <vector>
 
+#include "R.h"
 #include "TestHelpers.h"
 #include "androidfw/PosixUtils.h"
 #include "gmock/gmock.h"
@@ -127,10 +128,14 @@
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
-  ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020000 string/str1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000e -> 0x7f020001 string/str3"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f02000f -> 0x7f020002 string/str4"), std::string::npos);
+  ASSERT_NE(result->stdout.find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1"),
+            std::string::npos);
+  ASSERT_NE(result->stdout.find(R::target::string::literal::str1 + " -> 0x7f020000 string/str1"),
+            std::string::npos);
+  ASSERT_NE(result->stdout.find(R::target::string::literal::str3 + " -> 0x7f020001 string/str3"),
+            std::string::npos);
+  ASSERT_NE(result->stdout.find(R::target::string::literal::str4 + " -> 0x7f020002 string/str4"),
+            std::string::npos);
 
   // clang-format off
   result = ExecuteBinary({"idmap2",
@@ -297,7 +302,7 @@
                           "lookup",
                           "--idmap-path", GetIdmapPath(),
                           "--config", "",
-                          "--resid", "0x7f02000c"});  // string/str1
+                          "--resid", R::target::string::literal::str1});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index a2c1560..87da36c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -22,6 +22,8 @@
 #include <utility>
 #include <vector>
 
+#include "R.h"
+#include "TestConstants.h"
 #include "TestHelpers.h"
 #include "android-base/macros.h"
 #include "androidfw/ApkAssets.h"
@@ -36,6 +38,8 @@
 using ::testing::IsNull;
 using ::testing::NotNull;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace android::idmap2 {
 
 #define ASSERT_TARGET_ENTRY(entry, target_resid, type, value) \
@@ -168,7 +172,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                            /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
@@ -177,8 +181,8 @@
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829);
-  ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xc054fb26);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
+  ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
 }
@@ -220,7 +224,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                            /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
@@ -234,17 +238,21 @@
 
   const auto& target_entries = data->GetTargetEntries();
   ASSERT_EQ(target_entries.size(), 4U);
-  ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f010000);
-  ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000);
-  ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001);
-  ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002);
+  ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1,
+                      Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay::integer::int1);
+  ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay::string::str1);
+  ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay::string::str3);
+  ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay::string::str4);
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(target_entries.size(), 4U);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f010000, 0x7f010000);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x7f020000, 0x7f02000c);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x7f020001, 0x7f02000e);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x7f020002, 0x7f02000f);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay::integer::int1, R::target::integer::int1);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[1], R::overlay::string::str1, R::target::string::str1);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[2], R::overlay::string::str3, R::target::string::str3);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay::string::str4, R::target::string::str4);
 }
 
 TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
@@ -257,7 +265,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                            /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
   auto& idmap = *idmap_result;
@@ -271,17 +279,25 @@
 
   const auto& target_entries = data->GetTargetEntries();
   ASSERT_EQ(target_entries.size(), 4U);
-  ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00010000);
-  ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020000);
-  ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020001);
-  ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020002);
+  ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1,
+                      Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay_shared::integer::int1);
+  ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay_shared::string::str1);
+  ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay_shared::string::str3);
+  ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay_shared::string::str4);
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(target_entries.size(), 4U);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x00010000, 0x7f010000);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x00020000, 0x7f02000c);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x00020001, 0x7f02000e);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x00020002, 0x7f02000f);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay_shared::integer::int1,
+                       R::target::integer::int1);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[1], R::overlay_shared::string::str1,
+                       R::target::string::str1);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[2], R::overlay_shared::string::str3,
+                       R::target::string::str3);
+  ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay_shared::string::str4,
+                       R::target::string::str4);
 }
 
 TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) {
@@ -290,7 +306,7 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0x7f030001;  // xml/overlays_different_packages
   auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info,
-                                               PolicyFlags::POLICY_PUBLIC,
+                                               PolicyFlags::PUBLIC,
                                                /* enforce_overlayable */ false);
 
   ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage();
@@ -298,14 +314,14 @@
 
   const auto& target_entries = data->GetTargetEntries();
   ASSERT_EQ(target_entries.size(), 2U);
-  ASSERT_TARGET_ENTRY(target_entries[0], 0x7f02000c, Res_value::TYPE_REFERENCE,
-                      0x0104000a);  // string/str1 -> android:string/ok
-  ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE,
-                      0x7f020001);  // string/str3 -> string/str4
+  ASSERT_TARGET_ENTRY(target_entries[0], R::target::string::str1, Res_value::TYPE_REFERENCE,
+                      0x0104000a);  // -> android:string/ok
+  ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
+                      R::overlay::string::str3);
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(overlay_entries.size(), 1U);
-  ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f020001, 0x7f02000e);  // string/str3 <- string/str4
+  ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay::string::str3, R::target::string::str3);
 }
 
 TEST(IdmapTests, CreateIdmapDataInlineResources) {
@@ -314,7 +330,7 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0x7f030002;  // xml/overlays_inline
   auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info,
-                                               PolicyFlags::POLICY_PUBLIC,
+                                               PolicyFlags::PUBLIC,
                                                /* enforce_overlayable */ false);
 
   ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage();
@@ -323,10 +339,10 @@
   constexpr size_t overlay_string_pool_size = 8U;
   const auto& target_entries = data->GetTargetEntries();
   ASSERT_EQ(target_entries.size(), 2U);
-  ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_INT_DEC,
-                      73U);  // integer/int1 -> 73
-  ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_STRING,
-                      overlay_string_pool_size + 0U);  // string/str1 -> "Hello World"
+  ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, Res_value::TYPE_INT_DEC,
+                      73U);  // -> 73
+  ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_STRING,
+                      overlay_string_pool_size + 0U);  // -> "Hello World"
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(overlay_entries.size(), 0U);
@@ -346,7 +362,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  const auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  const auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                            /* enforce_overlayable */ true);
   ASSERT_FALSE(result);
 }
@@ -362,7 +378,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                      /* enforce_overlayable */ true);
   ASSERT_TRUE(result);
   const auto idmap = std::move(*result);
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
index eca7404..1b27759 100644
--- a/cmds/idmap2/tests/PoliciesTests.cpp
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -17,76 +17,96 @@
 #include <string>
 
 #include "TestHelpers.h"
+#include "androidfw/ResourceTypes.h"
 #include "gtest/gtest.h"
-#include "idmap2/Policies.h"
+#include "idmap2/PolicyUtils.h"
 
-using android::idmap2::PolicyBitmask;
-using android::idmap2::PolicyFlags;
+using android::idmap2::utils::BitmaskToPolicies;
+using android::idmap2::utils::PoliciesToBitmaskResult;
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
-TEST(PoliciesTests, PoliciesToBitmasks) {
-  const auto bitmask1 = PoliciesToBitmask({"system"});
+TEST(PoliciesTests, PoliciesToBitmaskResults) {
+  const auto bitmask1 = PoliciesToBitmaskResult({"system"});
   ASSERT_TRUE(bitmask1);
-  ASSERT_EQ(*bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
+  ASSERT_EQ(*bitmask1, PolicyFlags::SYSTEM_PARTITION);
 
-  const auto bitmask2 = PoliciesToBitmask({"system", "vendor"});
+  const auto bitmask2 = PoliciesToBitmaskResult({"system", "vendor"});
   ASSERT_TRUE(bitmask2);
-  ASSERT_EQ(*bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+  ASSERT_EQ(*bitmask2, PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION);
 
-  const auto bitmask3 = PoliciesToBitmask({"vendor", "system"});
+  const auto bitmask3 = PoliciesToBitmaskResult({"vendor", "system"});
   ASSERT_TRUE(bitmask3);
-  ASSERT_EQ(*bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+  ASSERT_EQ(*bitmask3, PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION);
 
-  const auto bitmask4 = PoliciesToBitmask({"odm", "oem", "public", "product", "system", "vendor"});
+  const auto bitmask4 =
+      PoliciesToBitmaskResult({"odm", "oem", "public", "product", "system", "vendor"});
   ASSERT_TRUE(bitmask4);
-  ASSERT_EQ(*bitmask4, PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
-                           PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
-                           PolicyFlags::POLICY_SYSTEM_PARTITION |
-                           PolicyFlags::POLICY_VENDOR_PARTITION);
+  ASSERT_EQ(*bitmask4, PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION |
+                           PolicyFlags::PUBLIC | PolicyFlags::PRODUCT_PARTITION |
+                           PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION);
 
-  const auto bitmask5 = PoliciesToBitmask({"system", "system", "system"});
+  const auto bitmask5 = PoliciesToBitmaskResult({"system", "system", "system"});
   ASSERT_TRUE(bitmask5);
-  ASSERT_EQ(*bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
+  ASSERT_EQ(*bitmask5, PolicyFlags::SYSTEM_PARTITION);
 
-  const auto bitmask6 = PoliciesToBitmask({""});
+  const auto bitmask6 = PoliciesToBitmaskResult({""});
   ASSERT_FALSE(bitmask6);
 
-  const auto bitmask7 = PoliciesToBitmask({"foo"});
+  const auto bitmask7 = PoliciesToBitmaskResult({"foo"});
   ASSERT_FALSE(bitmask7);
 
-  const auto bitmask8 = PoliciesToBitmask({"system", "foo"});
+  const auto bitmask8 = PoliciesToBitmaskResult({"system", "foo"});
   ASSERT_FALSE(bitmask8);
 
-  const auto bitmask9 = PoliciesToBitmask({"system", ""});
+  const auto bitmask9 = PoliciesToBitmaskResult({"system", ""});
   ASSERT_FALSE(bitmask9);
 
-  const auto bitmask10 = PoliciesToBitmask({"system "});
+  const auto bitmask10 = PoliciesToBitmaskResult({"system "});
   ASSERT_FALSE(bitmask10);
+
+  const auto bitmask11 = PoliciesToBitmaskResult({"signature"});
+  ASSERT_TRUE(bitmask11);
+  ASSERT_EQ(*bitmask11, PolicyFlags::SIGNATURE);
+
+  const auto bitmask12 = PoliciesToBitmaskResult({"actor"});
+  ASSERT_TRUE(bitmask12);
+  ASSERT_EQ(*bitmask12, PolicyFlags::ACTOR_SIGNATURE);
 }
 
 TEST(PoliciesTests, BitmaskToPolicies) {
-  const auto policies1 = BitmaskToPolicies(PolicyFlags::POLICY_PUBLIC);
+  const auto policies1 = BitmaskToPolicies(PolicyFlags::PUBLIC);
   ASSERT_EQ(1, policies1.size());
   ASSERT_EQ(policies1[0], "public");
 
-  const auto policies2 = BitmaskToPolicies(PolicyFlags::POLICY_SYSTEM_PARTITION |
-                                           PolicyFlags::POLICY_VENDOR_PARTITION);
+  const auto policies2 =
+      BitmaskToPolicies(PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION);
   ASSERT_EQ(2, policies2.size());
   ASSERT_EQ(policies2[0], "system");
   ASSERT_EQ(policies2[1], "vendor");
 
-  const auto policies3 = BitmaskToPolicies(
-      PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION |
-      PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
-      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+  const auto policies3 =
+      BitmaskToPolicies(PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION |
+                        PolicyFlags::PUBLIC | PolicyFlags::PRODUCT_PARTITION |
+                        PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION);
   ASSERT_EQ(2, policies2.size());
   ASSERT_EQ(policies3[0], "odm");
   ASSERT_EQ(policies3[1], "oem");
-  ASSERT_EQ(policies3[2], "public");
-  ASSERT_EQ(policies3[3], "product");
+  ASSERT_EQ(policies3[2], "product");
+  ASSERT_EQ(policies3[3], "public");
   ASSERT_EQ(policies3[4], "system");
   ASSERT_EQ(policies3[5], "vendor");
+
+  const auto policies4 = BitmaskToPolicies(PolicyFlags::SIGNATURE);
+  ASSERT_EQ(1, policies4.size());
+  ASSERT_EQ(policies4[0], "signature");
+
+  const auto policies5 = BitmaskToPolicies(PolicyFlags::ACTOR_SIGNATURE);
+  ASSERT_EQ(1, policies5.size());
+  ASSERT_EQ(policies5[0], "actor");
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 1d34e42..9a10079 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -18,19 +18,22 @@
 #include <sstream>
 #include <string>
 
+#include "R.h"
 #include "TestHelpers.h"
 #include "androidfw/ApkAssets.h"
 #include "androidfw/Idmap.h"
+#include "androidfw/ResourceTypes.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "idmap2/Idmap.h"
-#include "idmap2/Policies.h"
 #include "idmap2/PrettyPrintVisitor.h"
 
 using ::testing::NotNull;
 
 using android::ApkAssets;
-using android::idmap2::PolicyBitmask;
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
 
 namespace android::idmap2 {
 
@@ -43,7 +46,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap);
 
@@ -53,7 +56,8 @@
 
   ASSERT_NE(stream.str().find("target apk path  : "), std::string::npos);
   ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
-  ASSERT_NE(stream.str().find("0x7f010000 -> 0x7f010000 integer/int1\n"), std::string::npos);
+  ASSERT_NE(stream.str().find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1\n"),
+            std::string::npos);
 }
 
 TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
new file mode 100644
index 0000000..aed263a
--- /dev/null
+++ b/cmds/idmap2/tests/R.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_TESTS_R_H
+#define IDMAP2_TESTS_R_H
+
+#include <idmap2/ResourceUtils.h>
+
+namespace android::idmap2 {
+
+static std::string hexify(ResourceId id) {
+  std::stringstream stream;
+  stream << std::hex << static_cast<uint32_t>(id);
+  return stream.str();
+}
+
+// clang-format off
+namespace R::target {
+  namespace integer {
+    constexpr ResourceId int1 = 0x7f010000;
+
+    namespace literal {
+      inline const std::string int1 = hexify(R::target::integer::int1);
+    }
+  }
+
+  namespace string {
+    constexpr ResourceId not_overlayable = 0x7f020003;
+    constexpr ResourceId other = 0x7f020004;
+    constexpr ResourceId policy_actor = 0x7f020005;
+    constexpr ResourceId policy_odm = 0x7f020006;
+    constexpr ResourceId policy_oem = 0x7f020007;
+    constexpr ResourceId policy_product = 0x7f020008;
+    constexpr ResourceId policy_public = 0x7f020009;
+    constexpr ResourceId policy_signature = 0x7f02000a;
+    constexpr ResourceId policy_system = 0x7f02000b;
+    constexpr ResourceId policy_system_vendor = 0x7f02000c;
+    constexpr ResourceId str1 = 0x7f02000d;
+    constexpr ResourceId str3 = 0x7f02000f;
+    constexpr ResourceId str4 = 0x7f020010;
+
+    namespace literal {
+      inline const std::string str1 = hexify(R::target::string::str1);
+      inline const std::string str3 = hexify(R::target::string::str3);
+      inline const std::string str4 = hexify(R::target::string::str4);
+    }
+  }
+}
+
+namespace R::overlay {
+  namespace integer {
+    constexpr ResourceId int1 = 0x7f010000;
+  }
+  namespace string {
+    constexpr ResourceId str1 = 0x7f020000;
+    constexpr ResourceId str3 = 0x7f020001;
+    constexpr ResourceId str4 = 0x7f020002;
+  }
+}
+
+namespace R::overlay_shared {
+  namespace integer {
+    constexpr ResourceId int1 = 0x00010000;
+  }
+  namespace string {
+    constexpr ResourceId str1 = 0x00020000;
+    constexpr ResourceId str3 = 0x00020001;
+    constexpr ResourceId str4 = 0x00020002;
+  }
+}
+
+namespace R::system_overlay::string {
+  constexpr ResourceId policy_public = 0x7f010000;
+  constexpr ResourceId policy_system = 0x7f010001;
+  constexpr ResourceId policy_system_vendor = 0x7f010002;
+}
+
+namespace R::system_overlay_invalid::string {
+  constexpr ResourceId not_overlayable = 0x7f010000;
+  constexpr ResourceId other = 0x7f010001;
+  constexpr ResourceId policy_actor = 0x7f010002;
+  constexpr ResourceId policy_odm = 0x7f010003;
+  constexpr ResourceId policy_oem = 0x7f010004;
+  constexpr ResourceId policy_product = 0x7f010005;
+  constexpr ResourceId policy_public = 0x7f010006;
+  constexpr ResourceId policy_signature = 0x7f010007;
+  constexpr ResourceId policy_system = 0x7f010008;
+  constexpr ResourceId policy_system_vendor = 0x7f010009;
+};
+// clang-format on
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_TESTS_R_H
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index b22fdaf..5c5c81e 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -20,14 +20,20 @@
 #include <sstream>
 #include <string>
 
+#include "TestConstants.h"
 #include "TestHelpers.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/ResourceTypes.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/RawPrintVisitor.h"
 
+using android::base::StringPrintf;
 using ::testing::NotNull;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace android::idmap2 {
 
 #define ASSERT_CONTAINS_REGEX(pattern, str)                       \
@@ -48,7 +54,7 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+  const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ true);
   ASSERT_TRUE(idmap);
 
@@ -59,8 +65,12 @@
 #define ADDRESS "[0-9a-f]{8}: "
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000003  version\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "76a20829  target crc\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "c054fb26  overlay crc\n", stream.str());
+  ASSERT_CONTAINS_REGEX(
+      StringPrintf(ADDRESS "%s  target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
+      stream.str());
+  ASSERT_CONTAINS_REGEX(
+      StringPrintf(ADDRESS "%s  overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING),
+      stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "      7f  target package id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "      7f  overlay package id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  target entry count\n", stream.str());
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 39c4937..de039f4 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -22,7 +22,9 @@
 #include <utility>
 #include <vector>
 
+#include "R.h"
 #include "TestHelpers.h"
+#include "androidfw/ResourceTypes.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "idmap2/LogInfo.h"
@@ -31,6 +33,8 @@
 using android::Res_value;
 using android::idmap2::utils::ExtractOverlayManifestInfo;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace android::idmap2 {
 
 #define ASSERT_RESULT(r)                             \
@@ -106,20 +110,20 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0U;  // no xml
   auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
-                                          PolicyFlags::POLICY_PUBLIC,
+                                          PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
-  ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000,
-                              false /* rewrite */));  // integer/int1
-  ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000,
-                              false /* rewrite */));  // string/str1
-  ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001,
-                              false /* rewrite */));  // string/str3
-  ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002,
-                              false /* rewrite */));  // string/str4
+  ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE,
+                              R::overlay::integer::int1, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str1, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str3, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str4, false /* rewrite */));
 }
 
 TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
@@ -128,18 +132,18 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0x7f030003;  // xml/overlays_swap
   auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
-                                          PolicyFlags::POLICY_PUBLIC,
+                                          PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
-  ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002,
-                              true /* rewrite */));  // string/str1 -> string/str4
-  ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000,
-                              true /* rewrite */));  // string/str3 -> string/str1
-  ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001,
-                              true /* rewrite */));  // string/str4 -> string/str3
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE,
+                              R::overlay::string::str4, true /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
+                              R::overlay::string::str1, true /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE,
+                              R::overlay::string::str3, true /* rewrite */));
 }
 
 TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
@@ -148,17 +152,17 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0x7f030001;  // xml/overlays_different_packages
   auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
-                                          PolicyFlags::POLICY_PUBLIC,
+                                          PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U);
-  ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x0104000a,
-                              false /* rewrite */));  // string/str1 -> android:string/ok
-  ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001,
-                              true /* rewrite */));  // string/str3 -> string/str4
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x0104000a,
+                              false /* rewrite */));  // -> android:string/ok
+  ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE,
+                              0x7f020001, true /* rewrite */));
 }
 
 TEST(ResourceMappingTests, InlineResources) {
@@ -167,7 +171,7 @@
   info.target_name = "TestResources";
   info.resource_mapping = 0x7f030002;  // xml/overlays_inline
   auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info,
-                                          PolicyFlags::POLICY_PUBLIC,
+                                          PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
   constexpr size_t overlay_string_pool_size = 8U;
@@ -175,108 +179,120 @@
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
   ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
-  ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_STRING,
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_STRING,
                               overlay_string_pool_size + 0U,
-                              false /* rewrite */));  // string/str1 -> "Hello World"
-  ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_INT_DEC, 73U,
-                              false /* rewrite */));  // string/str1 -> "Hello World"
+                              false /* rewrite */));  // -> "Hello World"
+  ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U,
+                              false /* rewrite */));  // -> 73
 }
 
 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
   auto resources =
       TestGetResourceMapping("/target/target.apk", "/system-overlay/system-overlay.apk",
-                             PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                             PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
                              /* enforce_overlayable */ true);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
-  ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010000,
-                              false /* rewrite */));  // string/policy_public
-  ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010001,
-                              false /* rewrite */));  // string/policy_system
-  ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010002,
-                              false /* rewrite */));  // string/policy_system_vendor
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+                              R::system_overlay::string::policy_public, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+                              R::system_overlay::string::policy_system, false /* rewrite */));
+  ASSERT_RESULT(
+      MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+                    R::system_overlay::string::policy_system_vendor, false /* rewrite */));
 }
 
 // Resources that are not declared as overlayable and resources that a protected by policies the
 // overlay does not fulfill must not map to overlay resources.
 TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
-  auto resources = TestGetResourceMapping(
-      "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
-      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
-      /* enforce_overlayable */ true);
+  auto resources = TestGetResourceMapping("/target/target.apk",
+                                          "/system-overlay-invalid/system-overlay-invalid.apk",
+                                          PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
+                                          /* enforce_overlayable */ true);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U);
-  ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
-                              false /* rewrite */));  // string/policy_public
-  ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
-                              false /* rewrite */));  // string/policy_system
-  ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
-                              false /* rewrite */));  // string/policy_system_vendor
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_public,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_system,
+                              false /* rewrite */));
+  ASSERT_RESULT(
+      MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+                    R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
 }
 
 // Resources that are not declared as overlayable and resources that a protected by policies the
 // overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
 // off.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
-  auto resources = TestGetResourceMapping(
-      "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk",
-      PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
-      /* enforce_overlayable */ false);
+  auto resources = TestGetResourceMapping("/target/target.apk",
+                                          "/system-overlay-invalid/system-overlay-invalid.apk",
+                                          PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
+                                          /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
-  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U);
-  ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000,
-                              false /* rewrite */));  // string/not_overlayable
-  ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001,
-                              false /* rewrite */));  // string/other
-  ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002,
-                              false /* rewrite */));  // string/policy_odm
-  ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003,
-                              false /* rewrite */));  // string/policy_oem
-  ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004,
-                              false /* rewrite */));  // string/policy_product
-  ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
-                              false /* rewrite */));  // string/policy_public
-  ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006,
-                              false /* rewrite */));  // string/policy_signature
-  ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
-                              false /* rewrite */));  // string/policy_system
-  ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
-                              false /* rewrite */));  // string/policy_system_vendor
+  ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U);
+  ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::not_overlayable,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::other, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_actor,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_odm, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_oem, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_product,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_public,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_signature,
+                              false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+                              R::system_overlay_invalid::string::policy_system,
+                              false /* rewrite */));
+  ASSERT_RESULT(
+      MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+                    R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
 }
 
 // Overlays that do not target an <overlayable> tag can overlay resources defined within any
 // <overlayable> tag.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
   auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-no-name.apk",
-                                          PolicyFlags::POLICY_PUBLIC,
+                                          PolicyFlags::PUBLIC,
                                           /* enforce_overlayable */ false);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   auto& res = *resources;
   ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
-  ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000,
-                              false /* rewrite */));  // integer/int1
-  ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000,
-                              false /* rewrite */));  // string/str1
-  ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001,
-                              false /* rewrite */));  // string/str3
-  ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002,
-                              false /* rewrite */));  // string/str4
+  ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE,
+                              R::overlay::integer::int1, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str1, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str3, false /* rewrite */));
+  ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE,
+                              R::overlay::string::str4, false /* rewrite */));
 }
 
 // Overlays that are neither pre-installed nor signed with the same signature as the target cannot
 // overlay packages that have not defined overlayable resources.
 TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
-  auto resources =
-      TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay-no-name.apk",
-                             PolicyFlags::POLICY_PUBLIC,
-                             /* enforce_overlayable */ true);
+  auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
+                                          "/overlay/overlay-no-name.apk", PolicyFlags::PUBLIC,
+                                          /* enforce_overlayable */ true);
 
   ASSERT_TRUE(resources) << resources.GetErrorMessage();
   ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
@@ -293,33 +309,44 @@
 
     ASSERT_TRUE(resources) << resources.GetErrorMessage();
     auto& res = *resources;
-    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U);
-    ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000,
-                                false /* rewrite */));  // string/not_overlayable
-    ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001,
-                                false /* rewrite */));  // string/other
-    ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002,
-                                false /* rewrite */));  // string/policy_odm
-    ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003,
-                                false /* rewrite */));  // string/policy_oem
-    ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004,
-                                false /* rewrite */));  // string/policy_product
-    ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005,
-                                false /* rewrite */));  // string/policy_public
-    ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006,
-                                false /* rewrite */));  // string/policy_signature
-    ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007,
-                                false /* rewrite */));  // string/policy_system
-    ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008,
-                                false /* rewrite */));  // string/policy_system_vendor
+    ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+    ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::not_overlayable,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::other, false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_actor,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_odm,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_oem,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_product,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_public,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_signature,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+                                R::system_overlay_invalid::string::policy_system,
+                                false /* rewrite */));
+    ASSERT_RESULT(MappingExists(
+        res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+        R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
   };
 
-  CheckEntries(PolicyFlags::POLICY_SIGNATURE);
-  CheckEntries(PolicyFlags::POLICY_PRODUCT_PARTITION);
-  CheckEntries(PolicyFlags::POLICY_SYSTEM_PARTITION);
-  CheckEntries(PolicyFlags::POLICY_VENDOR_PARTITION);
-  CheckEntries(PolicyFlags::POLICY_ODM_PARTITION);
-  CheckEntries(PolicyFlags::POLICY_OEM_PARTITION);
+  CheckEntries(PolicyFlags::SIGNATURE);
+  CheckEntries(PolicyFlags::PRODUCT_PARTITION);
+  CheckEntries(PolicyFlags::SYSTEM_PARTITION);
+  CheckEntries(PolicyFlags::VENDOR_PARTITION);
+  CheckEntries(PolicyFlags::ODM_PARTITION);
+  CheckEntries(PolicyFlags::OEM_PARTITION);
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
new file mode 100644
index 0000000..6bc924e
--- /dev/null
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_TESTS_TESTCONSTANTS_H
+#define IDMAP2_TESTS_TESTCONSTANTS_H
+
+namespace android::idmap2::TestConstants {
+
+constexpr const auto TARGET_CRC = 0x41c60c8c;
+constexpr const auto TARGET_CRC_STRING = "41c60c8c";
+
+constexpr const auto OVERLAY_CRC = 0xc054fb26;
+constexpr const auto OVERLAY_CRC_STRING = "c054fb26";
+
+}  // namespace android::idmap2::TestConstants
+
+#endif  // IDMAP2_TESTS_TESTCONSTANTS_H
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
index 9ebfae4..7119d82 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -25,6 +25,7 @@
     <string name="policy_signature">policy_signature</string>
     <string name="policy_odm">policy_odm</string>
     <string name="policy_oem">policy_oem</string>
+    <string name="policy_actor">policy_actor</string>
 
     <!-- Requests to overlay a resource that is not declared as overlayable. -->
     <string name="not_overlayable">not_overlayable</string>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
index 1456e74..bd99098 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index 8389f56..ad4cd48 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -41,6 +41,10 @@
         <item type="string" name="policy_oem" />
     </policy>
 
+    <policy type="actor">
+        <item type="string" name="policy_actor" />
+    </policy>
+
     <!-- Resources publicly overlayable -->
     <policy type="public">
         <item type="string" name="policy_public" />
@@ -63,4 +67,4 @@
         <item type="string" name="other" />
     </policy>
 </overlayable>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index a892c98..5230e25 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -36,6 +36,7 @@
     <string name="policy_signature">policy_signature</string>
     <string name="policy_system">policy_system</string>
     <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_actor">policy_actor</string>
 
     <string name="other">other</string>
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 2eb7c47..58504a7 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 251cf46..c80e5eb 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index 77a56e5..9439e1d 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -237,33 +237,38 @@
 Reader::Reader(const int fd)
 {
     mFile = fdopen(fd, "r");
+    mBuffer = new char[1024];
     mStatus = mFile == nullptr ? "Invalid fd " + std::to_string(fd) : "";
 }
 
 Reader::~Reader()
 {
     if (mFile != nullptr) fclose(mFile);
+    free(mBuffer);
 }
 
 bool Reader::readLine(std::string* line) {
     if (mFile == nullptr) return false;
 
-    char* buf = nullptr;
     size_t len = 0;
-    ssize_t read = getline(&buf, &len, mFile);
+    ssize_t read = getline(&mBuffer, &len, mFile);
     if (read != -1) {
-        std::string s(buf);
+        std::string s(mBuffer);
         line->assign(trim(s, DEFAULT_NEWLINE));
-    } else if (errno == EINVAL) {
-        mStatus = "Bad Argument";
+        return true;
     }
-    free(buf);
-    return read != -1;
+    if (!feof(mFile)) {
+        mStatus = "Error reading file. Ferror: " + std::to_string(ferror(mFile));
+    }
+    return false;
 }
 
 bool Reader::ok(std::string* error) {
+    if (mStatus.empty()) {
+        return true;
+    }
     error->assign(mStatus);
-    return mStatus.empty();
+    return false;
 }
 
 // ==============================================================================
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index 09dc8e6..5812c60 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -117,6 +117,7 @@
 
 private:
     FILE* mFile;
+    char* mBuffer;
     std::string mStatus;
 };
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f36b855..5535b66 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -395,6 +395,7 @@
         SnapshotMergeReported snapshot_merge_reported = 255;
         ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended =
             256  [(module) = "framework"];
+        DisplayJankReported display_jank_reported = 257;
         SdkExtensionStatus sdk_extension_status = 354;
     }
 
@@ -980,6 +981,17 @@
 
     // The job id (as assigned by the app).
     optional int32 job_id = 6;
+
+    // One flag for each of the API constraints defined by Jobscheduler. Does not include implcit
+    // constraints as they are always assumed to be set.
+    optional bool has_charging_constraint = 7;
+    optional bool has_battery_not_low_constraint = 8;
+    optional bool has_storage_not_low_constraint = 9;
+    optional bool has_timing_delay_constraint = 10;
+    optional bool has_deadline_constraint = 11;
+    optional bool has_idle_constraint = 12;
+    optional bool has_connectivity_constraint = 13;
+    optional bool has_content_trigger_constraint = 14;
 }
 
 /**
@@ -8228,6 +8240,22 @@
 }
 
 /**
+ * Janky event as reported by SurfaceFlinger.
+ * This event is intended to be consumed by a Perfetto subscriber for
+ * automated trace collection.
+ *
+ * Logged from:
+ *    frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
+ */
+message DisplayJankReported {
+    // Informational field for how long the janky event lasted in milliseconds
+    optional int64 event_duration_millis = 1;
+    // Number of frame deadlines missed, where SurfaceFlinger failed to update
+    // the display on time.
+    optional int32 present_deadlines_missed = 2;
+}
+
+/**
  * Information about camera facing and API level usage.
  * Logged from:
  *   frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 316a018..ca22bf4 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -16,19 +16,19 @@
 
 package android.accessibilityservice;
 
+import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHtmlText;
+import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage;
 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
 
 import android.annotation.IntDef;
 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;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -62,7 +62,6 @@
 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
@@ -554,13 +553,6 @@
      */
     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.
      */
@@ -810,6 +802,8 @@
      * </p>
      * @return The animated image drawable, or null if the resource is invalid or the image
      * exceed the screen size.
+     *
+     * @hide
      */
     @Nullable
     public Drawable loadAnimatedImage(@NonNull Context context)  {
@@ -937,6 +931,8 @@
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
      * @return The localized and restricted html description.
+     *
+     * @hide
      */
     @Nullable
     public String loadHtmlDescription(@NonNull PackageManager packageManager) {
@@ -1421,103 +1417,4 @@
             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 a812f29..d2bdf80 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -16,14 +16,15 @@
 
 package android.accessibilityservice;
 
+import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHtmlText;
+import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.StringRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -31,17 +32,12 @@
 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
@@ -94,13 +90,6 @@
      */
     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.
      *
@@ -221,6 +210,8 @@
      *
      * @return The animated image drawable, or null if the resource is invalid or the image
      * exceed the screen size.
+     *
+     * @hide
      */
     @Nullable
     public Drawable loadAnimatedImage(@NonNull Context context) {
@@ -236,6 +227,8 @@
      * It filters the <img> tag which do not meet the custom specification and the <a> tag.
      *
      * @return The localized and restricted html description.
+     *
+     * @hide
      */
     @Nullable
     public String loadHtmlDescription(@NonNull PackageManager packageManager) {
@@ -305,103 +298,4 @@
         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/accessibilityservice/util/AccessibilityUtils.java b/core/java/android/accessibilityservice/util/AccessibilityUtils.java
new file mode 100644
index 0000000..fa32bb2
--- /dev/null
+++ b/core/java/android/accessibilityservice/util/AccessibilityUtils.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Collection of utilities for accessibility service.
+ *
+ * @hide
+ */
+public final class AccessibilityUtils {
+    private AccessibilityUtils() {}
+
+    // 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));
+
+    /**
+     * 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.
+     */
+    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.
+     */
+    @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.
+     */
+    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.
+     */
+    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/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/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 4f41f8b..969ea70 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -675,7 +675,7 @@
     @Override
     public int checkPermission(String permName, String pkgName) {
         return PermissionManager
-                .checkPackageNamePermission(permName, pkgName);
+                .checkPackageNamePermission(permName, pkgName, getUserId());
     }
 
     @Override
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/app/compat/ChangeIdStateCache.java b/core/java/android/app/compat/ChangeIdStateCache.java
new file mode 100644
index 0000000..9ef63f6
--- /dev/null
+++ b/core/java/android/app/compat/ChangeIdStateCache.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.compat;
+
+import android.app.PropertyInvalidatedCache;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * Handles caching of calls to {@link com.android.internal.compat.IPlatformCompat}
+ * @hide
+ */
+public final class ChangeIdStateCache
+        extends PropertyInvalidatedCache<ChangeIdStateQuery, Boolean> {
+    private static final String CACHE_KEY = "cache_key.is_compat_change_enabled";
+    private static final int MAX_ENTRIES = 20;
+    private static boolean sDisabled = false;
+
+    /** @hide */
+    public ChangeIdStateCache() {
+        super(MAX_ENTRIES, CACHE_KEY);
+    }
+
+    /**
+     * Disable cache.
+     *
+     * <p>Should only be used in unit tests.
+     * @hide
+     */
+    public static void disable() {
+        sDisabled = true;
+    }
+
+    /**
+     * Invalidate the cache.
+     *
+     * <p>Can only be called by the system server process.
+     * @hide
+     */
+    public static void invalidate() {
+        if (!sDisabled) {
+            PropertyInvalidatedCache.invalidateCache(CACHE_KEY);
+        }
+    }
+
+    @Override
+    protected Boolean recompute(ChangeIdStateQuery query) {
+        IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (query.type == ChangeIdStateQuery.QUERY_BY_PACKAGE_NAME) {
+                return platformCompat.isChangeEnabledByPackageName(query.changeId,
+                                                                   query.packageName,
+                                                                   query.userId);
+            } else if (query.type == ChangeIdStateQuery.QUERY_BY_UID) {
+                return platformCompat.isChangeEnabledByUid(query.changeId, query.uid);
+            } else {
+                throw new IllegalArgumentException("Invalid query type: " + query.type);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        throw new IllegalStateException("Could not recompute value!");
+    }
+}
diff --git a/core/java/android/app/compat/ChangeIdStateQuery.java b/core/java/android/app/compat/ChangeIdStateQuery.java
new file mode 100644
index 0000000..3c245b1
--- /dev/null
+++ b/core/java/android/app/compat/ChangeIdStateQuery.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.compat;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.Immutable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+
+/**
+ * A key type for caching calls to {@link com.android.internal.compat.IPlatformCompat}
+ *
+ * <p>For {@link com.android.internal.compat.IPlatformCompat#isChangeEnabledByPackageName}
+ * and {@link com.android.internal.compat.IPlatformCompat#isChangeEnabledByUid}
+ *
+ * @hide
+ */
+@Immutable
+final class ChangeIdStateQuery {
+
+    static final int QUERY_BY_PACKAGE_NAME = 0;
+    static final int QUERY_BY_UID = 1;
+    @IntDef({QUERY_BY_PACKAGE_NAME, QUERY_BY_UID})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface QueryType {}
+
+    public @QueryType int type;
+    public long changeId;
+    public String packageName;
+    public int uid;
+    public int userId;
+
+    private ChangeIdStateQuery(@QueryType int type, long changeId, String packageName,
+                               int uid, int userId) {
+        this.type = type;
+        this.changeId = changeId;
+        this.packageName = packageName;
+        this.uid = uid;
+        this.userId = userId;
+    }
+
+    static ChangeIdStateQuery byPackageName(long changeId, @NonNull String packageName,
+                                            int userId) {
+        return new ChangeIdStateQuery(QUERY_BY_PACKAGE_NAME, changeId, packageName, 0, userId);
+    }
+
+    static ChangeIdStateQuery byUid(long changeId, int uid) {
+        return new ChangeIdStateQuery(QUERY_BY_UID, changeId, null, uid, 0);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if ((other == null) || !(other instanceof ChangeIdStateQuery)) {
+            return false;
+        }
+        final ChangeIdStateQuery that = (ChangeIdStateQuery) other;
+        return this.type == that.type
+            && this.changeId == that.changeId
+            && Objects.equals(this.packageName, that.packageName)
+            && this.uid == that.uid
+            && this.userId == that.userId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, changeId, packageName, uid, userId);
+    }
+}
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index e289a27..0d5e45f 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -19,14 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.compat.Compatibility;
-import android.content.Context;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 
-import com.android.internal.compat.IPlatformCompat;
-
 /**
  * CompatChanges APIs - to be used by platform code only (including mainline
  * modules).
@@ -35,6 +29,7 @@
  */
 @SystemApi
 public final class CompatChanges {
+    private static final ChangeIdStateCache QUERY_CACHE = new ChangeIdStateCache();
     private CompatChanges() {}
 
     /**
@@ -69,17 +64,8 @@
      */
     public static boolean isChangeEnabled(long changeId, @NonNull String packageName,
             @NonNull UserHandle user) {
-        IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
-                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return platformCompat.isChangeEnabledByPackageName(changeId, packageName,
-                    user.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        return QUERY_CACHE.query(ChangeIdStateQuery.byPackageName(changeId, packageName,
+                                                           user.getIdentifier()));
     }
 
     /**
@@ -101,15 +87,7 @@
      * @return {@code true} if the change is enabled for the current app.
      */
     public static boolean isChangeEnabled(long changeId, int uid) {
-        IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
-                ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return platformCompat.isChangeEnabledByUid(changeId, uid);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid));
     }
+
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b748cfa..c7f42cb 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3827,6 +3827,18 @@
         return queryArgs;
     }
 
+    /** @hide */
+    public static @NonNull Bundle includeSqlSelectionArgs(@NonNull Bundle queryArgs,
+            @Nullable String selection, @Nullable String[] selectionArgs) {
+        if (selection != null) {
+            queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);
+        }
+        if (selectionArgs != null) {
+            queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
+        }
+        return queryArgs;
+    }
+
     /**
      * Returns structured sort args formatted as an SQL sort clause.
      *
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 55a6cab..62815dd 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -138,6 +138,7 @@
      *
      * @hide
      */
+    @NonNull
     public final String packageName;
 
     /**
@@ -145,6 +146,7 @@
      *
      * @hide
      */
+    @NonNull
     public final String targetPackageName;
 
     /**
@@ -165,6 +167,7 @@
      * Full path to the base APK for this overlay package
      * @hide
      */
+    @NonNull
     public final String baseCodePath;
 
     /**
@@ -292,6 +295,7 @@
         return targetOverlayableName;
     }
 
+    @SuppressWarnings("ConstantConditions")
     private void ensureValidState() {
         if (packageName == null) {
             throw new IllegalArgumentException("packageName must not be null");
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 4246b84..34cc856 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -16,6 +16,7 @@
 
 package android.database;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentValues;
@@ -1548,4 +1549,24 @@
         }
         return -1;
     }
+
+    /**
+     * Escape the given argument for use in a {@code LIKE} statement.
+     * @hide
+     */
+    public static String escapeForLike(@NonNull String arg) {
+        // Shamelessly borrowed from com.android.providers.media.util.DatabaseUtils
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < arg.length(); i++) {
+            final char c = arg.charAt(i);
+            switch (c) {
+                case '%': sb.append('\\');
+                    break;
+                case '_': sb.append('\\');
+                    break;
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
 }
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/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 743ce7b..85ef4a3 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -131,9 +131,17 @@
     }
 
     /**
-     * Return the list of combinations of currently connected camera devices identifiers, which
+     * Return the set of combinations of currently connected camera device identifiers, which
      * support configuring camera device sessions concurrently.
      *
+     * <p>The devices in these combinations can be concurrently configured by the same
+     * client camera application. Using these camera devices concurrently by two different
+     * applications is not guaranteed to be supported, however.</p>
+     *
+     * <p>Each device in a combination, is guaranteed to support stream combinations which may be
+     * obtained by querying {@link #getCameraCharacteristics} for the key
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS}.</p>
+     *
      * <p>The set of combinations may include camera devices that may be in use by other camera API
      * clients.</p>
      *
@@ -174,7 +182,7 @@
      * to be used for exploring the entire space of supported concurrent stream combinations. The
      * available mandatory concurrent stream combinations may be obtained by querying
      * {@link #getCameraCharacteristics} for the key
-     * SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS. </p>
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS}. </p>
      *
      * <p>Note that session parameters will be ignored and calls to
      * {@link SessionConfiguration#setSessionParameters} are not required.</p>
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index ef76c62..bf641d7 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -28,6 +28,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -43,6 +44,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Enrollment information about the different available keyphrases.
@@ -116,7 +118,12 @@
     /**
      * List of available keyphrases.
      */
-    final private KeyphraseMetadata[] mKeyphrases;
+    private final KeyphraseMetadata[] mKeyphrases;
+
+    /**
+     * Set of UIDs associated with the detected enrollment applications.
+     */
+    private final Set<Integer> mEnrollmentApplicationUids;
 
     /**
      * Map between KeyphraseMetadata and the package name of the enrollment app that provides it.
@@ -136,11 +143,13 @@
             mParseError = "No enrollment applications found";
             mKeyphrasePackageMap = Collections.<KeyphraseMetadata, String>emptyMap();
             mKeyphrases = null;
+            mEnrollmentApplicationUids = Collections.emptySet();
             return;
         }
 
         List<String> parseErrors = new LinkedList<String>();
         mKeyphrasePackageMap = new HashMap<KeyphraseMetadata, String>();
+        mEnrollmentApplicationUids = new ArraySet<>();
         for (ResolveInfo ri : ris) {
             try {
                 ApplicationInfo ai = pm.getApplicationInfo(
@@ -162,6 +171,7 @@
                         getKeyphraseMetadataFromApplicationInfo(pm, ai, parseErrors);
                 if (metadata != null) {
                     mKeyphrasePackageMap.put(metadata, ai.packageName);
+                    mEnrollmentApplicationUids.add(ai.uid);
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 String error = "error parsing voice enrollment meta-data for "
@@ -372,9 +382,22 @@
         return null;
     }
 
+    /**
+     * Tests if the input UID matches a supported enrollment application.
+     *
+     * @param uid UID of the caller to test against.
+     * @return Returns true if input uid matches the uid of a supported enrollment application.
+     *         False if not.
+     */
+    public boolean isUidSupportedEnrollmentApplication(int uid) {
+        Log.d(TAG, "isUidSupportedEnrollmentApplication: " + toString());
+        return mEnrollmentApplicationUids.contains(uid);
+    }
+
     @Override
     public String toString() {
-        return "KeyphraseEnrollmentInfo [Keyphrases=" + mKeyphrasePackageMap.toString()
+        return "KeyphraseEnrollmentInfo [KeyphrasePackageMap=" + mKeyphrasePackageMap.toString()
+                + ", enrollmentApplicationUids=" + mEnrollmentApplicationUids.toString()
                 + ", ParseError=" + mParseError + "]";
     }
 }
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 9327b24..e9de274 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -53,6 +53,7 @@
     private static final int DO_FINISH_SESSION = 110;
     private static final int DO_VIEW_CLICKED = 115;
     private static final int DO_NOTIFY_IME_HIDDEN = 120;
+    private static final int DO_REMOVE_IME_SURFACE = 130;
 
     @UnsupportedAppUsage
     HandlerCaller mCaller;
@@ -136,6 +137,10 @@
                 mInputMethodSession.notifyImeHidden();
                 return;
             }
+            case DO_REMOVE_IME_SURFACE: {
+                mInputMethodSession.removeImeSurface();
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -184,6 +189,11 @@
     }
 
     @Override
+    public void removeImeSurface() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_IME_SURFACE));
+    }
+
+    @Override
     public void updateCursor(Rect newCursor) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageO(DO_UPDATE_CURSOR, newCursor));
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index f0b1eaa..b52b437 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -219,22 +219,29 @@
             case DO_REVOKE_SESSION:
                 inputMethod.revokeSession((InputMethodSession)msg.obj);
                 return;
-            case DO_SHOW_SOFT_INPUT:
-                SomeArgs args = (SomeArgs)msg.obj;
+            case DO_SHOW_SOFT_INPUT: {
+                final SomeArgs args = (SomeArgs)msg.obj;
                 inputMethod.showSoftInputWithToken(
                         msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
+                args.recycle();
                 return;
-            case DO_HIDE_SOFT_INPUT:
-                inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
+            }
+            case DO_HIDE_SOFT_INPUT: {
+                final SomeArgs args = (SomeArgs) msg.obj;
+                inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
+                        (IBinder) args.arg1);
+                args.recycle();
                 return;
+            }
             case DO_CHANGE_INPUTMETHOD_SUBTYPE:
                 inputMethod.changeInputMethodSubtype((InputMethodSubtype)msg.obj);
                 return;
             case DO_CREATE_INLINE_SUGGESTIONS_REQUEST:
-                args = (SomeArgs) msg.obj;
+                final SomeArgs args = (SomeArgs) msg.obj;
                 inputMethod.onCreateInlineSuggestionsRequest(
                         (InlineSuggestionsRequestInfo) args.arg1,
                         (IInlineSuggestionsRequestCallback) args.arg2);
+                args.recycle();
                 return;
 
         }
@@ -380,9 +387,9 @@
 
     @BinderThread
     @Override
-    public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
-                flags, resultReceiver));
+    public void hideSoftInput(IBinder hideInputToken, int flags, ResultReceiver resultReceiver) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_HIDE_SOFT_INPUT,
+                flags, hideInputToken, resultReceiver));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 20a4ab3..27839e7 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -459,6 +459,16 @@
      */
     private IBinder mCurShowInputToken;
 
+    /**
+     * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#hideSoftInput}
+     * The original app window token is passed from client app window.
+     * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique dummy
+     * token to identify this window.
+     * This dummy token is only valid for a single call to {@link InputMethodImpl#hideSoftInput},
+     * after which it is set {@code null} until next call.
+     */
+    private IBinder mCurHideInputToken;
+
     final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
         onComputeInsets(mTmpInsets);
         if (isExtractViewShown()) {
@@ -500,6 +510,7 @@
     public class InputMethodImpl extends AbstractInputMethodImpl {
 
         private boolean mSystemCallingShowSoftInput;
+        private boolean mSystemCallingHideSoftInput;
 
         /**
          * {@inheritDoc}
@@ -636,11 +647,32 @@
 
         /**
          * {@inheritDoc}
+         * @hide
+         */
+        @MainThread
+        @Override
+        public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
+                IBinder hideInputToken) {
+            mSystemCallingHideSoftInput = true;
+            mCurHideInputToken = hideInputToken;
+            hideSoftInput(flags, resultReceiver);
+            mCurHideInputToken = null;
+            mSystemCallingHideSoftInput = false;
+        }
+
+        /**
+         * {@inheritDoc}
          */
         @MainThread
         @Override
         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
+            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
+                    && !mSystemCallingHideSoftInput) {
+                Log.e(TAG, "IME shouldn't call hideSoftInput on itself."
+                        + " Use requestHideSelf(int) itself");
+                return;
+            }
             final boolean wasVisible = mIsPreRendered
                     ? mDecorViewVisible && mWindowVisible : isInputViewShown();
             applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */);
@@ -738,6 +770,15 @@
         public void setCurrentShowInputToken(IBinder showInputToken) {
             mCurShowInputToken = showInputToken;
         }
+
+        /**
+         * {@inheritDoc}
+         * @hide
+         */
+        @Override
+        public void setCurrentHideInputToken(IBinder hideInputToken) {
+            mCurHideInputToken = hideInputToken;
+        }
     }
 
     // TODO(b/137800469): Add detailed docs explaining the inline suggestions process.
@@ -814,6 +855,13 @@
         onPreRenderedWindowVisibilityChanged(false /* setVisible */);
     }
 
+    private void removeImeSurface() {
+        if (!mShowInputRequested && !mWindowVisible) {
+            // hiding a window removes its surface.
+            mWindow.hide();
+        }
+    }
+
     private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
         mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
     }
@@ -932,6 +980,14 @@
         public final void notifyImeHidden() {
             InputMethodService.this.notifyImeHidden();
         }
+
+        /**
+         * Notify IME that surface can be now removed.
+         * @hide
+         */
+        public final void removeImeSurface() {
+            InputMethodService.this.removeImeSurface();
+        }
     }
     
     /**
@@ -2157,7 +2213,8 @@
         if (!isVisibilityAppliedUsingInsetsConsumer()) {
             return;
         }
-        mPrivOps.applyImeVisibility(mCurShowInputToken, setVisible);
+        mPrivOps.applyImeVisibility(setVisible
+                ? mCurShowInputToken : mCurHideInputToken, setVisible);
     }
 
     private boolean isVisibilityAppliedUsingInsetsConsumer() {
diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
index 31c948a..ef138a0 100644
--- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
+++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java
@@ -296,6 +296,12 @@
             // no-op for multi-session since IME is responsible controlling navigation bar buttons.
             reportNotSupported();
         }
+
+        @Override
+        public void removeImeSurface() {
+            // no-op for multi-session
+            reportNotSupported();
+        }
     }
 
     private static final class MultiClientInputMethodSessionImpl
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 5d6dc7b..0bd211d 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -561,21 +561,24 @@
     private static final class PackageNamePermissionQuery {
         final String permName;
         final String pkgName;
+        final int uid;
 
-        PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName) {
+        PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, int uid) {
             this.permName = permName;
             this.pkgName = pkgName;
+            this.uid = uid;
         }
 
         @Override
         public String toString() {
-            return String.format("PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s\")",
-                    pkgName, permName);
+            return String.format(
+                    "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, uid=%s\")",
+                    pkgName, permName, uid);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hashCode(permName) * 13 + Objects.hashCode(pkgName);
+            return Objects.hash(permName, pkgName, uid);
         }
 
         @Override
@@ -590,15 +593,17 @@
                 return false;
             }
             return Objects.equals(permName, other.permName)
-                    && Objects.equals(pkgName, other.pkgName);
+                    && Objects.equals(pkgName, other.pkgName)
+                    && uid == other.uid;
         }
     }
 
     /* @hide */
-    private static int checkPackageNamePermissionUncached(String permName, String pkgName) {
+    private static int checkPackageNamePermissionUncached(
+            String permName, String pkgName, int uid) {
         try {
             return ActivityThread.getPermissionManager().checkPermission(
-                    permName, pkgName, UserHandle.myUserId());
+                    permName, pkgName, uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -611,7 +616,8 @@
                     16, CACHE_KEY_PACKAGE_INFO) {
                 @Override
                 protected Integer recompute(PackageNamePermissionQuery query) {
-                    return checkPackageNamePermissionUncached(query.permName, query.pkgName);
+                    return checkPackageNamePermissionUncached(
+                            query.permName, query.pkgName, query.uid);
                 }
             };
 
@@ -620,9 +626,9 @@
      *
      * @hide
      */
-    public static int checkPackageNamePermission(String permName, String pkgName) {
+    public static int checkPackageNamePermission(String permName, String pkgName, int uid) {
         return sPackageNamePermissionCache.query(
-                new PackageNamePermissionQuery(permName, pkgName));
+                new PackageNamePermissionQuery(permName, pkgName, uid));
     }
 
     /**
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index fb8406e..a9addba 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -17,6 +17,7 @@
 package android.service.autofill;
 
 import android.annotation.NonNull;
+import android.annotation.Size;
 import android.app.slice.Slice;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -24,6 +25,8 @@
 
 import com.android.internal.util.DataClass;
 
+import java.util.List;
+
 /**
  * Wrapper class holding a {@link Slice} and an {@link InlinePresentationSpec} for rendering UI
  * for an Inline Suggestion.
@@ -50,6 +53,18 @@
      */
     private final boolean mPinned;
 
+    /**
+     * Returns the autofill hints set in the slice.
+     *
+     * @hide
+     */
+    @NonNull
+    @Size(min = 0)
+    public String[] getAutofillHints() {
+        List<String> hints = mSlice.getHints();
+        return hints.toArray(new String[hints.size()]);
+    }
+
 
 
     // Code below generated by codegen v1.0.14.
@@ -214,10 +229,10 @@
     };
 
     @DataClass.Generated(
-            time = 1579726472535L,
+            time = 1582753782651L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java",
-            inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+            inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size(min=0L) java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
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/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index 68ba63a..b7fdf5a 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.os.Bundle;
 import android.service.autofill.Dataset;
+import android.service.autofill.InlinePresentation;
 
 import com.android.internal.util.DataClass;
 
@@ -52,6 +53,13 @@
     private @Nullable List<Dataset> mInlineSuggestions;
 
     /**
+     * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
+     * inline actions are provided.
+     */
+    @DataClass.PluralOf("inlineAction")
+    private @Nullable List<InlinePresentation> mInlineActions;
+
+    /**
      * The client state that {@link AugmentedAutofillService} implementation can put anything in to
      * identify the request and the response when calling
      * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -66,6 +74,10 @@
         return null;
     }
 
+    private static List<InlinePresentation> defaultInlineActions() {
+        return null;
+    }
+
     private static Bundle defaultClientState() {
         return null;
     }
@@ -74,6 +86,7 @@
     /** @hide */
     abstract static class BaseBuilder {
         abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value);
+        abstract FillResponse.Builder addInlineAction(@NonNull InlinePresentation value);
     }
 
 
@@ -95,9 +108,11 @@
     /* package-private */ FillResponse(
             @Nullable FillWindow fillWindow,
             @Nullable List<Dataset> inlineSuggestions,
+            @Nullable List<InlinePresentation> inlineActions,
             @Nullable Bundle clientState) {
         this.mFillWindow = fillWindow;
         this.mInlineSuggestions = inlineSuggestions;
+        this.mInlineActions = inlineActions;
         this.mClientState = clientState;
 
         // onConstructed(); // You can define this method to get a callback
@@ -125,6 +140,17 @@
     }
 
     /**
+     * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
+     * inline actions are provided.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @Nullable List<InlinePresentation> getInlineActions() {
+        return mInlineActions;
+    }
+
+    /**
      * The client state that {@link AugmentedAutofillService} implementation can put anything in to
      * identify the request and the response when calling
      * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -145,6 +171,7 @@
 
         private @Nullable FillWindow mFillWindow;
         private @Nullable List<Dataset> mInlineSuggestions;
+        private @Nullable List<InlinePresentation> mInlineActions;
         private @Nullable Bundle mClientState;
 
         private long mBuilderFieldsSet = 0L;
@@ -185,6 +212,27 @@
         }
 
         /**
+         * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
+         * inline actions are provided.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setInlineActions(@Nullable List<InlinePresentation> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mInlineActions = value;
+            return this;
+        }
+
+        /** @see #setInlineActions */
+        @DataClass.Generated.Member
+        @Override
+        @NonNull FillResponse.Builder addInlineAction(@NonNull InlinePresentation value) {
+            if (mInlineActions == null) setInlineActions(new ArrayList<>());
+            mInlineActions.add(value);
+            return this;
+        }
+
+        /**
          * The client state that {@link AugmentedAutofillService} implementation can put anything in to
          * identify the request and the response when calling
          * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -192,7 +240,7 @@
         @DataClass.Generated.Member
         public @NonNull Builder setClientState(@Nullable Bundle value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4;
+            mBuilderFieldsSet |= 0x8;
             mClientState = value;
             return this;
         }
@@ -200,7 +248,7 @@
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull FillResponse build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x8; // Mark builder used
+            mBuilderFieldsSet |= 0x10; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mFillWindow = defaultFillWindow();
@@ -209,17 +257,21 @@
                 mInlineSuggestions = defaultInlineSuggestions();
             }
             if ((mBuilderFieldsSet & 0x4) == 0) {
+                mInlineActions = defaultInlineActions();
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
                 mClientState = defaultClientState();
             }
             FillResponse o = new FillResponse(
                     mFillWindow,
                     mInlineSuggestions,
+                    mInlineActions,
                     mClientState);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x8) != 0) {
+            if ((mBuilderFieldsSet & 0x10) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -227,10 +279,10 @@
     }
 
     @DataClass.Generated(
-            time = 1580335256422L,
+            time = 1582682935951L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java",
-            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlinePresentation> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  java.util.List<android.service.autofill.InlinePresentation> defaultInlineActions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlinePresentation)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
index de90b94..2a809b1 100644
--- a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -47,7 +46,6 @@
  * CarrierMessagingService.
  * @hide
  */
-@SystemApi
 public abstract class CarrierMessagingServiceWrapper {
     // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
     // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
@@ -64,7 +62,6 @@
      * @return true upon successfully binding to a carrier messaging service, false otherwise
      * @hide
      */
-    @SystemApi
     public boolean bindToCarrierMessagingService(@NonNull Context context,
             @NonNull String carrierPackageName) {
         Preconditions.checkState(mCarrierMessagingServiceConnection == null);
@@ -82,7 +79,6 @@
      * @param context the context
      * @hide
      */
-    @SystemApi
     public void disposeConnection(@NonNull Context context) {
         Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
         context.unbindService(mCarrierMessagingServiceConnection);
@@ -93,7 +89,6 @@
      * Implemented by subclasses to use the carrier messaging service once it is ready.
      * @hide
      */
-    @SystemApi
     public abstract void onServiceReady();
 
     /**
@@ -117,7 +112,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
             int subId, @NonNull final CarrierMessagingCallbackWrapper callback) {
         if (mICarrierMessagingService != null) {
@@ -142,7 +136,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
             int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) {
         if (mICarrierMessagingService != null) {
@@ -168,7 +161,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
             int destPort, int sendSmsFlag,
             @NonNull final CarrierMessagingCallbackWrapper callback) {
@@ -194,7 +186,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
             @NonNull String destAddress, int sendSmsFlag,
             @NonNull final CarrierMessagingCallbackWrapper callback) {
@@ -220,7 +211,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
             @NonNull final CarrierMessagingCallbackWrapper callback) {
         if (mICarrierMessagingService != null) {
@@ -244,7 +234,6 @@
      * @param callback the callback to notify upon completion
      * @hide
      */
-    @SystemApi
     public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
             @NonNull final CarrierMessagingCallbackWrapper callback) {
         if (mICarrierMessagingService != null) {
@@ -276,7 +265,6 @@
      * {@link CarrierMessagingServiceWrapper}.
      * @hide
      */
-    @SystemApi
     public abstract static class CarrierMessagingCallbackWrapper {
 
         /**
@@ -289,7 +277,6 @@
          *               {@see CarrierMessagingService#onReceiveTextSms}.
          * @hide
          */
-        @SystemApi
         public void onFilterComplete(int result) {
 
         }
@@ -304,7 +291,6 @@
          *                   only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
          * @hide
          */
-        @SystemApi
         public void onSendSmsComplete(int result, int messageRef) {
 
         }
@@ -319,7 +305,6 @@
          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
          * @hide
          */
-        @SystemApi
         public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
 
         }
@@ -334,7 +319,6 @@
          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
          * @hide
          */
-        @SystemApi
         public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
 
         }
@@ -346,7 +330,6 @@
          *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
          * @hide
          */
-        @SystemApi
         public void onDownloadMmsComplete(int result) {
 
         }
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 ca40974..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/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index a88d389..7d070b1 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -227,7 +227,6 @@
     @Nullable
     private KeyphraseMetadata mKeyphraseMetadata;
     private final KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
-    private final IVoiceInteractionService mVoiceInteractionService;
     private final IVoiceInteractionManagerService mModelManagementService;
     private final SoundTriggerListener mInternalCallback;
     private final Callback mExternalCallback;
@@ -413,14 +412,11 @@
      * @param text The keyphrase text to get the detector for.
      * @param locale The java locale for the detector.
      * @param callback A non-null Callback for receiving the recognition events.
-     * @param voiceInteractionService The current voice interaction service.
      * @param modelManagementService A service that allows management of sound models.
-     *
      * @hide
      */
     public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
             KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
-            IVoiceInteractionService voiceInteractionService,
             IVoiceInteractionManagerService modelManagementService) {
         mText = text;
         mLocale = locale;
@@ -428,7 +424,6 @@
         mExternalCallback = callback;
         mHandler = new MyHandler();
         mInternalCallback = new SoundTriggerListener(mHandler);
-        mVoiceInteractionService = voiceInteractionService;
         mModelManagementService = modelManagementService;
         new RefreshAvailabiltyTask().execute();
     }
@@ -471,6 +466,8 @@
     /**
      * Get the audio capabilities supported by the platform which can be enabled when
      * starting a recognition.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @see #AUDIO_CAPABILITY_ECHO_CANCELLATION
      * @see #AUDIO_CAPABILITY_NOISE_SUPPRESSION
@@ -488,7 +485,7 @@
     private int getSupportedAudioCapabilitiesLocked() {
         try {
             ModuleProperties properties =
-                    mModelManagementService.getDspModuleProperties(mVoiceInteractionService);
+                    mModelManagementService.getDspModuleProperties();
             if (properties != null) {
                 return properties.audioCapabilities;
             }
@@ -501,6 +498,8 @@
 
     /**
      * Starts recognition for the associated keyphrase.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
      * @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
@@ -533,6 +532,8 @@
 
     /**
      * Stops recognition for the associated keyphrase.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @return Indicates whether the call succeeded or not.
      * @throws UnsupportedOperationException if the recognition isn't supported.
@@ -565,6 +566,8 @@
      * stopping recognition. Once the model is unloaded, the value will be lost.
      * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before calling this
      * method.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @param modelParam   {@link ModelParams}
      * @param value        Value to set
@@ -595,6 +598,8 @@
      * value is returned. See {@link ModelParams} for parameter default values.
      * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before
      * calling this method.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @param modelParam   {@link ModelParams}
      * @return value of parameter
@@ -617,6 +622,8 @@
      * Determine if parameter control is supported for the given model handle.
      * This method should be checked prior to calling {@link AlwaysOnHotwordDetector#setParameter}
      * or {@link AlwaysOnHotwordDetector#getParameter}.
+     * Caller must be the active voice interaction service via
+     * Settings.Secure.VOICE_INTERACTION_SERVICE.
      *
      * @param modelParam {@link ModelParams}
      * @return supported range of parameter, null if not supported
@@ -775,7 +782,7 @@
 
         int code = STATUS_ERROR;
         try {
-            code = mModelManagementService.startRecognition(mVoiceInteractionService,
+            code = mModelManagementService.startRecognition(
                     mKeyphraseMetadata.id, mLocale.toLanguageTag(), mInternalCallback,
                     new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
                             recognitionExtra, null /* additional data */, audioCapabilities));
@@ -791,8 +798,8 @@
     private int stopRecognitionLocked() {
         int code = STATUS_ERROR;
         try {
-            code = mModelManagementService.stopRecognition(
-                    mVoiceInteractionService, mKeyphraseMetadata.id, mInternalCallback);
+            code = mModelManagementService.stopRecognition(mKeyphraseMetadata.id,
+                    mInternalCallback);
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in stopRecognition!", e);
         }
@@ -805,8 +812,8 @@
 
     private int setParameterLocked(@ModelParams int modelParam, int value) {
         try {
-            int code = mModelManagementService.setParameter(mVoiceInteractionService,
-                    mKeyphraseMetadata.id, modelParam, value);
+            int code = mModelManagementService.setParameter(mKeyphraseMetadata.id, modelParam,
+                    value);
 
             if (code != STATUS_OK) {
                 Slog.w(TAG, "setParameter failed with error code " + code);
@@ -820,8 +827,7 @@
 
     private int getParameterLocked(@ModelParams int modelParam) {
         try {
-            return mModelManagementService.getParameter(mVoiceInteractionService,
-                    mKeyphraseMetadata.id, modelParam);
+            return mModelManagementService.getParameter(mKeyphraseMetadata.id, modelParam);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -831,8 +837,7 @@
     private ModelParamRange queryParameterLocked(@ModelParams int modelParam) {
         try {
             SoundTrigger.ModelParamRange modelParamRange =
-                    mModelManagementService.queryParameter(mVoiceInteractionService,
-                            mKeyphraseMetadata.id, modelParam);
+                    mModelManagementService.queryParameter(mKeyphraseMetadata.id, modelParam);
 
             if (modelParamRange == null) {
                 return null;
@@ -966,7 +971,7 @@
             ModuleProperties dspModuleProperties = null;
             try {
                 dspModuleProperties =
-                        mModelManagementService.getDspModuleProperties(mVoiceInteractionService);
+                        mModelManagementService.getDspModuleProperties();
             } catch (RemoteException e) {
                 Slog.w(TAG, "RemoteException in getDspProperties!", e);
             }
@@ -982,7 +987,7 @@
         private void internalUpdateEnrolledKeyphraseMetadata() {
             try {
                 mKeyphraseMetadata = mModelManagementService.getEnrolledKeyphraseMetadata(
-                        mVoiceInteractionService, mText, mLocale.toLanguageTag());
+                        mText, mLocale.toLanguageTag());
             } catch (RemoteException e) {
                 Slog.w(TAG, "RemoteException in internalUpdateEnrolledKeyphraseMetadata", e);
             }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index fc99836..b54e4d9 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -199,7 +199,7 @@
             throw new IllegalStateException("Not available until onReady() is called");
         }
         try {
-            mSystemService.showSession(mInterface, args, flags);
+            mSystemService.showSession(args, flags);
         } catch (RemoteException e) {
         }
     }
@@ -302,7 +302,7 @@
             // Allow only one concurrent recognition via the APIs.
             safelyShutdownHotwordDetector();
             mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
-                    mKeyphraseEnrollmentInfo, mInterface, mSystemService);
+                    mKeyphraseEnrollmentInfo, mSystemService);
         }
         return mHotwordDetector;
     }
@@ -373,7 +373,7 @@
         }
 
         try {
-            mSystemService.setUiHints(mInterface, hints);
+            mSystemService.setUiHints(hints);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 2c077bb..7238b12 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -18,7 +18,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
@@ -62,7 +61,6 @@
  *
  * @hide
  */
-@SystemApi
 @TestApi
 public class TelephonyRegistryManager {
 
@@ -286,7 +284,6 @@
      * @param incomingNumber incoming phone number.
      * @hide
      */
-    @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void notifyCallStateChangedForAllSubscriptions(@CallState int state,
@@ -302,7 +299,6 @@
      * Notify {@link SubscriptionInfo} change.
      * @hide
      */
-    @SystemApi
     public void notifySubscriptionInfoChanged() {
         try {
             sRegistry.notifySubscriptionInfoChanged();
@@ -315,7 +311,6 @@
      * Notify opportunistic {@link SubscriptionInfo} change.
      * @hide
      */
-    @SystemApi
     public void notifyOpportunisticSubscriptionInfoChanged() {
         try {
             sRegistry.notifyOpportunisticSubscriptionInfoChanged();
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/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index f226369..43afc15 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -17,7 +17,6 @@
 package android.view;
 
 import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.toPublicType;
 
 import android.annotation.Nullable;
 import android.inputmethodservice.InputMethodService;
@@ -99,6 +98,15 @@
         }
     }
 
+    @Override
+    void hide(boolean animationFinished) {
+        super.hide();
+        if (animationFinished) {
+            // remove IME surface as IME has finished hide animation.
+            removeSurface();
+        }
+    }
+
     /**
      * Request {@link InputMethodManager} to show the IME.
      * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}.
@@ -128,6 +136,11 @@
     }
 
     @Override
+    public void removeSurface() {
+        getImm().removeImeSurface();
+    }
+
+    @Override
     public void setControl(@Nullable InsetsSourceControl control, int[] showTypes,
             int[] hideTypes) {
         super.setControl(control, showTypes, hideTypes);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 4a6a5a0..65ea6bb 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -694,7 +694,7 @@
         if (shown) {
             showDirectly(controller.getTypes());
         } else {
-            hideDirectly(controller.getTypes());
+            hideDirectly(controller.getTypes(), true /* animationFinished */);
         }
     }
 
@@ -852,10 +852,10 @@
                         : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
     }
 
-    private void hideDirectly(@InsetsType int types) {
+    private void hideDirectly(@InsetsType int types, boolean animationFinished) {
         final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
         for (int i = internalTypes.size() - 1; i >= 0; i--) {
-            getSourceConsumer(internalTypes.valueAt(i)).hide();
+            getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished);
         }
     }
 
@@ -887,7 +887,7 @@
         if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
             showDirectly(types);
         } else {
-            hideDirectly(types);
+            hideDirectly(types, false /* animationFinished */);
         }
         if (mViewRoot.mView == null) {
             return;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index e6497c0..e3a7de1 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsState.toPublicType;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
-import android.util.MutableShort;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type.InsetsType;
@@ -137,6 +135,10 @@
         setRequestedVisible(false);
     }
 
+    void hide(boolean animationFinished) {
+        hide();
+    }
+
     /**
      * Called when current window gains focus
      */
@@ -201,6 +203,13 @@
     }
 
     /**
+     * Remove surface on which this consumer type is drawn.
+     */
+    public void removeSurface() {
+        // no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
+    }
+
+    /**
      * Sets requested visibility from the client, regardless of whether we are able to control it at
      * the moment.
      */
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/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 024de4d..cb0320e 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -69,6 +69,9 @@
     /** The type of the UI. */
     private final @NonNull @Type String mType;
 
+    /** Whether the suggestion should be pinned or not. */
+    private final boolean mPinned;
+
     /**
      * Creates a new {@link InlineSuggestionInfo}, for testing purpose.
      *
@@ -79,8 +82,8 @@
     public static InlineSuggestionInfo newInlineSuggestionInfo(
             @NonNull InlinePresentationSpec presentationSpec,
             @NonNull @Source String source,
-            @Nullable String[] autofillHints) {
-        return new InlineSuggestionInfo(presentationSpec, source, autofillHints, TYPE_SUGGESTION);
+            @Nullable String[] autofillHints, @NonNull @Type String type, boolean isPinned) {
+        return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned);
     }
 
 
@@ -127,6 +130,8 @@
      *   Hints for the type of data being suggested.
      * @param type
      *   The type of the UI.
+     * @param pinned
+     *   Whether the suggestion should be pinned or not.
      * @hide
      */
     @DataClass.Generated.Member
@@ -134,7 +139,8 @@
             @NonNull InlinePresentationSpec presentationSpec,
             @NonNull @Source String source,
             @Nullable String[] autofillHints,
-            @NonNull @Type String type) {
+            @NonNull @Type String type,
+            boolean pinned) {
         this.mPresentationSpec = presentationSpec;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPresentationSpec);
@@ -163,6 +169,7 @@
 
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mType);
+        this.mPinned = pinned;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -199,6 +206,14 @@
         return mType;
     }
 
+    /**
+     * Whether the suggestion should be pinned or not.
+     */
+    @DataClass.Generated.Member
+    public boolean isPinned() {
+        return mPinned;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -209,7 +224,8 @@
                 "presentationSpec = " + mPresentationSpec + ", " +
                 "source = " + mSource + ", " +
                 "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + ", " +
-                "type = " + mType +
+                "type = " + mType + ", " +
+                "pinned = " + mPinned +
         " }";
     }
 
@@ -229,7 +245,8 @@
                 && java.util.Objects.equals(mPresentationSpec, that.mPresentationSpec)
                 && java.util.Objects.equals(mSource, that.mSource)
                 && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints)
-                && java.util.Objects.equals(mType, that.mType);
+                && java.util.Objects.equals(mType, that.mType)
+                && mPinned == that.mPinned;
     }
 
     @Override
@@ -243,6 +260,7 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mSource);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints);
         _hash = 31 * _hash + java.util.Objects.hashCode(mType);
+        _hash = 31 * _hash + Boolean.hashCode(mPinned);
         return _hash;
     }
 
@@ -253,6 +271,7 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
+        if (mPinned) flg |= 0x10;
         if (mAutofillHints != null) flg |= 0x4;
         dest.writeByte(flg);
         dest.writeTypedObject(mPresentationSpec, flags);
@@ -273,6 +292,7 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         byte flg = in.readByte();
+        boolean pinned = (flg & 0x10) != 0;
         InlinePresentationSpec presentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR);
         String source = in.readString();
         String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray();
@@ -306,6 +326,7 @@
 
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mType);
+        this.mPinned = pinned;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -325,10 +346,10 @@
     };
 
     @DataClass.Generated(
-            time = 1579806757327L,
+            time = 1582753084046L,
             codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java",
-            inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+            inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final  boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 71c9e33..869a929 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -348,6 +348,27 @@
      * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN InputMethodManager.RESULT_UNCHANGED_HIDDEN},
      * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
      * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
+     * @param hideInputToken an opaque {@link android.os.Binder} token to identify which API call
+     *         of {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}} is associated
+     *         with this callback.
+     * @hide
+     */
+    @MainThread
+    public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
+            IBinder hideInputToken);
+
+    /**
+     * Request that any soft input part of the input method be hidden from the user.
+     * @param flags Provides additional information about the show request.
+     * Currently always 0.
+     * @param resultReceiver The client requesting the show may wish to
+     * be told the impact of their request, which should be supplied here.
+     * The result code should be
+     * {@link InputMethodManager#RESULT_UNCHANGED_SHOWN InputMethodManager.RESULT_UNCHANGED_SHOWN},
+     * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN
+     *        InputMethodManager.RESULT_UNCHANGED_HIDDEN},
+     * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
+     * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
      */
     @MainThread
     public void hideSoftInput(int flags, ResultReceiver resultReceiver);
@@ -366,4 +387,13 @@
      * @hide
      */
     public void setCurrentShowInputToken(IBinder showInputToken);
+
+    /**
+     * Update token of the client window requesting {@link #hideSoftInput(int, ResultReceiver)}
+     * @param hideInputToken dummy app window token for window requesting
+     *        {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}
+     * @hide
+     */
+    public void setCurrentHideInputToken(IBinder hideInputToken);
+
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 39d5f5c..f3aa314 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1709,7 +1709,7 @@
             }
 
             try {
-                return mService.hideSoftInput(mClient, flags, resultReceiver);
+                return mService.hideSoftInput(mClient, windowToken, flags, resultReceiver);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -1986,7 +1986,8 @@
     @UnsupportedAppUsage
     void closeCurrentInput() {
         try {
-            mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
+            mService.hideSoftInput(
+                    mClient, mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2056,6 +2057,21 @@
     }
 
     /**
+     * Notify IME directly to remove surface as it is no longer visible.
+     * @hide
+     */
+    public void removeImeSurface() {
+        synchronized (mH) {
+            try {
+                if (mCurMethod != null) {
+                    mCurMethod.removeImeSurface();
+                }
+            } catch (RemoteException re) {
+            }
+        }
+    }
+
+    /**
      * Report the current selection range.
      *
      * <p><strong>Editor authors</strong>, you need to call this method whenever
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index eb81628..0d688ff 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -191,4 +191,10 @@
      * @hide
      */
     public void notifyImeHidden();
+
+    /**
+     * Notify IME directly to remove surface as it is no longer visible.
+     * @hide
+     */
+    public void removeImeSurface();
 }
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/Magnifier.java b/core/java/android/widget/Magnifier.java
index a299b01..8ea824d 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -353,8 +353,9 @@
 
             // Gets the startX for new style, which should be bounded by the horizontal bounds.
             // Also calculates the left/right cut width for pixel copy.
-            leftBound += mViewCoordinatesInSurface[0];
-            rightBound += mViewCoordinatesInSurface[0];
+            leftBound = Math.max(leftBound + mViewCoordinatesInSurface[0], 0);
+            rightBound = Math.min(
+                rightBound + mViewCoordinatesInSurface[0], mContentCopySurface.mWidth);
             mLeftCutWidth = Math.max(0, leftBound - startX);
             mRightCutWidth = Math.max(0, startX + mSourceWidth - rightBound);
             startX = Math.max(startX, leftBound);
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/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index dc6942c..6a0b443 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -71,8 +71,8 @@
 
     void noteSyncStart(String name, int uid);
     void noteSyncFinish(String name, int uid);
-    void noteJobStart(String name, int uid, int standbyBucket, int jobid);
-    void noteJobFinish(String name, int uid, int stopReason, int standbyBucket, int jobid);
+    void noteJobStart(String name, int uid);
+    void noteJobFinish(String name, int uid, int stopReason);
 
     void noteStartWakelock(int uid, int pid, String name, String historyName,
             int type, boolean unimportantForLogging);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 417e23f..71ee8af 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -33,7 +33,7 @@
 import android.service.voice.IVoiceInteractionSession;
 
 interface IVoiceInteractionManagerService {
-    void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
+    void showSession(in Bundle sessionArgs, int flags);
     boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
             IVoiceInteractor interactor);
     boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
@@ -52,68 +52,91 @@
     /**
      * Gets the registered Sound model for keyphrase detection for the current user.
      * May be null if no matching sound model exists.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
      *
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param bcp47Locale The BCP47 language tag  for the keyphrase's locale.
+     * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES
      */
     @UnsupportedAppUsage
     SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, in String bcp47Locale);
     /**
-     * Add/Update the given keyphrase sound model.
+     * Add/Update the given keyphrase sound model for the current user.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
+     *
+     * @param model The keyphrase sound model to store peristantly.
+     * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES
      */
     int updateKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel model);
     /**
      * Deletes the given keyphrase sound model for the current user.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
      *
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param bcp47Locale The BCP47 language tag  for the keyphrase's locale.
+     * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES
      */
     int deleteKeyphraseSoundModel(int keyphraseId, in String bcp47Locale);
 
     /**
      * Gets the properties of the DSP hardware on this device, null if not present.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      */
-    SoundTrigger.ModuleProperties getDspModuleProperties(in IVoiceInteractionService service);
+    SoundTrigger.ModuleProperties getDspModuleProperties();
     /**
      * Indicates if there's a keyphrase sound model available for the given keyphrase ID and the
      * user ID of the caller.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      *
-     * @param service The current VoiceInteractionService.
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param bcp47Locale The BCP47 language tag  for the keyphrase's locale.
      */
-    boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
-            String bcp47Locale);
+    boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale);
     /**
      * Generates KeyphraseMetadata for an enrolled sound model based on keyphrase string, locale,
      * and the user ID of the caller.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      *
-     * @param service The current VoiceInteractionService
      * @param keyphrase Keyphrase text associated with the enrolled model
      * @param bcp47Locale The BCP47 language tag for the keyphrase's locale.
      * @return The metadata for the enrolled voice model bassed on the passed in parameters. Null if
      *         no matching voice model exists.
      */
-    KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service,
-            String keyphrase, String bcp47Locale);
+    KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase, String bcp47Locale);
     /**
      * Starts a recognition for the given keyphrase.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      */
-    int startRecognition(in IVoiceInteractionService service, int keyphraseId,
-            in String bcp47Locale, in IRecognitionStatusCallback callback,
+    int startRecognition(int keyphraseId, in String bcp47Locale,
+            in IRecognitionStatusCallback callback,
             in SoundTrigger.RecognitionConfig recognitionConfig);
     /**
      * Stops a recognition for the given keyphrase.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      */
-    int stopRecognition(in IVoiceInteractionService service, int keyphraseId,
-            in IRecognitionStatusCallback callback);
+    int stopRecognition(int keyphraseId, in IRecognitionStatusCallback callback);
     /**
      * Set a model specific ModelParams with the given value. This
      * parameter will keep its value for the duration the model is loaded regardless of starting and
      * stopping recognition. Once the model is unloaded, the value will be lost.
      * queryParameter should be checked first before calling this method.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      *
-     * @param service The current VoiceInteractionService.
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param modelParam   ModelParams
      * @param value        Value to set
@@ -123,36 +146,37 @@
      *         - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
      *           if API is not supported by HAL
      */
-    int setParameter(in IVoiceInteractionService service, int keyphraseId,
-            in ModelParams modelParam, int value);
+    int setParameter(int keyphraseId, in ModelParams modelParam, int value);
     /**
      * Get a model specific ModelParams. This parameter will keep its value
      * for the duration the model is loaded regardless of starting and stopping recognition.
      * Once the model is unloaded, the value will be lost. If the value is not set, a default
      * value is returned. See ModelParams for parameter default values.
      * queryParameter should be checked first before calling this method.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      *
-     * @param service The current VoiceInteractionService.
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param modelParam   ModelParams
      * @return value of parameter
      */
-    int getParameter(in IVoiceInteractionService service, int keyphraseId,
-            in ModelParams modelParam);
+    int getParameter(int keyphraseId, in ModelParams modelParam);
     /**
      * Determine if parameter control is supported for the given model handle.
      * This method should be checked prior to calling setParameter or getParameter.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      *
-     * @param service The current VoiceInteractionService.
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param modelParam ModelParams
      * @return supported range of parameter, null if not supported
      */
-    @nullable SoundTrigger.ModelParamRange queryParameter(in IVoiceInteractionService service,
-            int keyphraseId, in ModelParams modelParam);
+    @nullable SoundTrigger.ModelParamRange queryParameter(int keyphraseId,
+            in ModelParams modelParam);
 
     /**
      * @return the component name for the currently active voice interaction service
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     ComponentName getActiveServiceComponentName();
 
@@ -164,59 +188,70 @@
      * @param sourceFlags flags indicating the source of this show
      * @param showCallback optional callback to be notified when the session was shown
      * @param activityToken optional token of activity that needs to be on top
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     boolean showSessionForActiveService(in Bundle args, int sourceFlags,
             IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken);
 
     /**
      * Hides the session from the active service, if it is showing.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     void hideCurrentSession();
 
     /**
      * Notifies the active service that a launch was requested from the Keyguard. This will only
      * be called if {@link #activeServiceSupportsLaunchFromKeyguard()} returns true.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     void launchVoiceAssistFromKeyguard();
 
     /**
      * Indicates whether there is a voice session running (but not necessarily showing).
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     boolean isSessionRunning();
 
     /**
      * Indicates whether the currently active voice interaction service is capable of handling the
      * assist gesture.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     boolean activeServiceSupportsAssist();
 
     /**
      * Indicates whether the currently active voice interaction service is capable of being launched
      * from the lockscreen.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     boolean activeServiceSupportsLaunchFromKeyguard();
 
     /**
      * Called when the lockscreen got shown.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     void onLockscreenShown();
 
     /**
      * Register a voice interaction listener.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener);
 
     /**
      * Checks the availability of a set of voice actions for the current active voice service.
      * Returns all supported voice actions.
+     * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE
      */
     void getActiveServiceSupportedActions(in List<String> voiceActions,
      in IVoiceActionCheckCallback callback);
 
     /**
      * Provide hints for showing UI.
+     * Caller must be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
      */
-    void setUiHints(in IVoiceInteractionService service, in Bundle hints);
+    void setUiHints(in Bundle hints);
 
     /**
      * Requests a list of supported actions from a specific activity.
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index ef9b3d10..73ef8c6 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
 import android.graphics.Point;
@@ -38,6 +39,7 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
 import android.provider.MetadataReader;
 import android.system.Int64Ref;
 import android.text.TextUtils;
@@ -333,15 +335,17 @@
         if (isDirectory) {
             FileUtils.deleteContents(file);
         }
-        if (!file.delete()) {
+        // We could be deleting pending media which doesn't have any content yet, so only throw
+        // if the file exists and we fail to delete it.
+        if (file.exists() && !file.delete()) {
             throw new IllegalStateException("Failed to delete " + file);
         }
 
         onDocIdChanged(docId);
-        removeFromMediaStore(visibleFile, isDirectory);
+        removeFromMediaStore(visibleFile);
     }
 
-    private void removeFromMediaStore(@Nullable File visibleFile, boolean isFolder)
+    private void removeFromMediaStore(@Nullable File visibleFile)
             throws FileNotFoundException {
         // visibleFolder is null if we're removing a document from external thumb drive or SD card.
         if (visibleFile != null) {
@@ -350,21 +354,19 @@
             try {
                 final ContentResolver resolver = getContext().getContentResolver();
                 final Uri externalUri = MediaStore.Files.getContentUri("external");
+                final Bundle queryArgs = new Bundle();
+                queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE);
 
-                // Remove media store entries for any files inside this directory, using
-                // path prefix match. Logic borrowed from MtpDatabase.
-                if (isFolder) {
-                    final String path = visibleFile.getAbsolutePath() + "/";
-                    resolver.delete(externalUri,
-                            "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
-                            new String[]{path + "%", Integer.toString(path.length()), path});
-                }
-
-                // Remove media store entry for this exact file.
-                final String path = visibleFile.getAbsolutePath();
-                resolver.delete(externalUri,
-                        "_data LIKE ?1 AND lower(_data)=lower(?2)",
-                        new String[]{path, path});
+                // Remove the media store entry corresponding to visibleFile and if it is a
+                // directory, also remove media store entries for any files inside this directory.
+                // Logic borrowed from com.android.providers.media.scan.ModernMediaScanner.
+                final String pathEscapedForLike = DatabaseUtils.escapeForLike(
+                        visibleFile.getAbsolutePath());
+                ContentResolver.includeSqlSelectionArgs(queryArgs,
+                        FileColumns.DATA + " LIKE ? ESCAPE '\\' OR "
+                                + FileColumns.DATA + " LIKE ? ESCAPE '\\'",
+                        new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
+                resolver.delete(externalUri, queryArgs);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 20cd7c2..9a22686 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -41,5 +41,5 @@
     boolean shouldOfferSwitchingToNextInputMethod();
     void notifyUserAction();
     void reportPreRendered(in EditorInfo info);
-    void applyImeVisibility(IBinder showInputToken, boolean setVisible);
+    void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible);
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 9eeef96..e5475f8 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -371,18 +371,20 @@
     /**
      * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean)}.
      *
-     * @param showInputToken dummy token that maps to window requesting
-     *        {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)}
+     * @param showOrHideInputToken dummy token that maps to window requesting
+     *        {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or
+     *        {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow
+     *        (IBinder, int)}
      * @param setVisible {@code true} to set IME visible, else hidden.
      */
     @AnyThread
-    public void applyImeVisibility(IBinder showInputToken, boolean setVisible) {
+    public void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
             return;
         }
         try {
-            ops.applyImeVisibility(showInputToken, setVisible);
+            ops.applyImeVisibility(showOrHideInputToken, setVisible);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
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/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 75eb4aa..140c410 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -55,11 +55,8 @@
     protected void saveLog(LogMaker log) {
         // TODO(b/116684537): Flag guard logging to event log and statsd socket.
         EventLogTags.writeSysuiMultiAction(log.serialize());
-        if (log.getCategory() != MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER
-                && log.getCategory() != MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM) {
-            FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM,
-                    /* UID is retrieved from statsd side */ 0, log.getEntries());
-        }
+        FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM,
+                /* UID is retrieved from statsd side */ 0, log.getEntries());
     }
 
     public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index fd4b5ab..40e4f4d 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -55,7 +55,7 @@
 
     void showSoftInput(in IBinder showInputToken, int flags, in ResultReceiver resultReceiver);
 
-    void hideSoftInput(int flags, in ResultReceiver resultReceiver);
+    void hideSoftInput(in IBinder hideInputToken, int flags, in ResultReceiver resultReceiver);
 
     void changeInputMethodSubtype(in InputMethodSubtype subtype);
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 0337ddd..3f03f2a 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -43,7 +43,7 @@
 
     boolean showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
             in ResultReceiver resultReceiver);
-    boolean hideSoftInput(in IInputMethodClient client, int flags,
+    boolean hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
             in ResultReceiver resultReceiver);
     // If windowToken is null, this just does startInput().  Otherwise this reports that a window
     // has gained focus, and if 'attribute' is non-null then also does startInput.
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 664643c..0319e36 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -50,4 +50,6 @@
     void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo);
 
     void notifyImeHidden();
+
+    void removeImeSurface();
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d27be27..ade2c7d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -208,7 +208,6 @@
                 "libseccomp_policy",
                 "libgrallocusage",
                 "libscrypt_static",
-                "libstatssocket",
             ],
 
             shared_libs: [
@@ -266,6 +265,7 @@
                 "libdl",
                 "libdl_android",
                 "libstatslog",
+                "libstatssocket",
                 "libtimeinstate",
                 "server_configurable_flags",
                 "libstatspull",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index e4141e0..359fd48 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -626,12 +626,6 @@
 
   // Set the jemalloc decay time to 1.
   mallopt(M_DECAY_TIME, 1);
-
-  // Maybe initialize GWP-ASan here. Must be called after
-  // mallopt(M_SET_ZYGOTE_CHILD).
-  bool ForceEnableGwpAsan = false;
-  android_mallopt(M_INITIALIZE_GWP_ASAN, &ForceEnableGwpAsan,
-                  sizeof(ForceEnableGwpAsan));
 }
 
 static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) {
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index d2bf205..41863bb 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -34,5 +34,5 @@
     STOP_REASON_TIMEOUT = 3;
     STOP_REASON_DEVICE_IDLE = 4;
     STOP_REASON_DEVICE_THERMAL = 5;
-    STOP_REASON_RESTRAINED = 6;
+    STOP_REASON_RESTRICTED_BUCKET = 6;
 }
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 6850d01..0455d58 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -225,9 +225,10 @@
     message ScreenBrightnessSettingLimitsProto {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-        optional int32 setting_minimum = 1;
-        optional int32 setting_maximum = 2;
-        optional int32 setting_default = 3;
+        reserved 1, 2, 3; // setting_minimum, setting_maximum, setting_default
+        optional float setting_minimum_float = 4;
+        optional float setting_maximum_float = 5;
+        optional float setting_default_float = 6;
     }
 
     // True to decouple auto-suspend mode from the display state.
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/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index 4d98603..b6671db 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -18,5 +18,8 @@
     <privapp-permissions package="com.android.documentsui">
         <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <!-- Permissions required for reading and logging compat changes -->
+        <permission name="android.permission.LOG_COMPAT_CHANGE"/>
+        <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
     </privapp-permissions>
 </permissions>
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..623bd13
--- /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/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 3f2f349..f87f98a 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -191,4 +191,3 @@
     shared_libs: common_test_libs,
     data: ["tests/data/**/*.apk"],
 }
-
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 35cebd4..2bfc7fc 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -22,6 +22,7 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/LocaleData.h>
+#include <androidfw/StringPiece.h>
 #include <utils/Errors.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -34,6 +35,7 @@
 
 #include <android/configuration.h>
 
+#include <array>
 #include <memory>
 
 namespace android {
@@ -1676,42 +1678,64 @@
  */
 struct ResTable_overlayable_policy_header
 {
-  struct ResChunk_header header;
-
+  /**
+   * Flags for a bitmask for all possible overlayable policy options.
+   *
+   * Any changes to this set should also update aidl/android/os/OverlayablePolicy.aidl
+   */
   enum PolicyFlags : uint32_t {
+    // Base
+    NONE = 0x00000000,
+
     // Any overlay can overlay these resources.
-    POLICY_PUBLIC = 0x00000001,
+    PUBLIC = 0x00000001,
 
     // The overlay must reside of the system partition or must have existed on the system partition
     // before an upgrade to overlay these resources.
-    POLICY_SYSTEM_PARTITION = 0x00000002,
+    SYSTEM_PARTITION = 0x00000002,
 
     // The overlay must reside of the vendor partition or must have existed on the vendor partition
     // before an upgrade to overlay these resources.
-    POLICY_VENDOR_PARTITION = 0x00000004,
+    VENDOR_PARTITION = 0x00000004,
 
     // The overlay must reside of the product partition or must have existed on the product
     // partition before an upgrade to overlay these resources.
-    POLICY_PRODUCT_PARTITION = 0x00000008,
+    PRODUCT_PARTITION = 0x00000008,
 
-    // The overlay must be signed with the same signature as the actor of the target resource,
-    // which can be separate or the same as the target package with the resource.
-    POLICY_SIGNATURE = 0x00000010,
+    // The overlay must be signed with the same signature as the package containing the target
+    // resource
+    SIGNATURE = 0x00000010,
 
     // The overlay must reside of the odm partition or must have existed on the odm
     // partition before an upgrade to overlay these resources.
-    POLICY_ODM_PARTITION = 0x00000020,
+    ODM_PARTITION = 0x00000020,
 
     // The overlay must reside of the oem partition or must have existed on the oem
     // partition before an upgrade to overlay these resources.
-    POLICY_OEM_PARTITION = 0x00000040,
+    OEM_PARTITION = 0x00000040,
+
+    // The overlay must be signed with the same signature as the actor declared for the target
+    // resource
+    ACTOR_SIGNATURE = 0x00000080,
   };
-  uint32_t policy_flags;
+
+  using PolicyBitmask = uint32_t;
+
+  struct ResChunk_header header;
+
+  PolicyFlags policy_flags;
 
   // The number of ResTable_ref that follow this header.
   uint32_t entry_count;
 };
 
+inline ResTable_overlayable_policy_header::PolicyFlags& operator |=(
+    ResTable_overlayable_policy_header::PolicyFlags& first,
+    ResTable_overlayable_policy_header::PolicyFlags second) {
+  first = static_cast<ResTable_overlayable_policy_header::PolicyFlags>(first | second);
+  return first;
+}
+
 #pragma pack(push, 1)
 struct Idmap_header {
   // Always 0x504D4449 ('IDMP')
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 8615069..2d69dfe 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -41,6 +41,8 @@
 using ::testing::SizeIs;
 using ::testing::StrEq;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace android {
 
 TEST(LoadedArscTest, LoadSinglePackageArsc) {
@@ -240,29 +242,29 @@
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
   EXPECT_THAT(info->actor, Eq("overlay://theme"));
-  EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+  EXPECT_THAT(info->policy_flags, Eq(PolicyFlags::PUBLIC));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
   EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags,
-              Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
-                 | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+              Eq(PolicyFlags::SYSTEM_PARTITION
+                 | PolicyFlags::PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->name, Eq("OverlayableResources2"));
   EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
   EXPECT_THAT(info->policy_flags,
-              Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
-                 | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+              Eq(PolicyFlags::VENDOR_PARTITION
+                 | PolicyFlags::PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
   EXPECT_THAT(info->name, Eq("OverlayableResources1"));
   EXPECT_THAT(info->actor, Eq("overlay://theme"));
   ASSERT_THAT(info, NotNull());
-  EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+  EXPECT_THAT(info->policy_flags, Eq(PolicyFlags::PUBLIC));
 }
 
 TEST(LoadedArscTest, ResourceIdentifierIterator) {
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/media/java/android/media/voice/KeyphraseModelManager.java b/media/java/android/media/voice/KeyphraseModelManager.java
index 3fa38e0..8ec8967 100644
--- a/media/java/android/media/voice/KeyphraseModelManager.java
+++ b/media/java/android/media/voice/KeyphraseModelManager.java
@@ -37,7 +37,8 @@
  * manage voice based sound trigger models.
  * Callers of this class are expected to have whitelist manifest permission MANAGE_VOICE_KEYPHRASES.
  * Callers of this class are expected to be the designated voice interaction service via
- * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
+ * {@link Settings.Secure.VOICE_INTERACTION_SERVICE} or a bundled voice model enrollment application
+ * detected by {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
  * @hide
  */
 @SystemApi
@@ -65,6 +66,10 @@
      * {@link #updateKeyphraseSoundModel}.
      * If the active voice interaction service changes from the current user, all requests will be
      * rejected, and any registered models will be unregistered.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
      *
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param locale The locale language tag supported by the desired model.
@@ -93,6 +98,10 @@
      * will be overwritten with the new model.
      * If the active voice interaction service changes from the current user, all requests will be
      * rejected, and any registered models will be unregistered.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
      *
      * @param model Keyphrase sound model to be updated.
      * @throws ServiceSpecificException Thrown with error code if failed to update the keyphrase
@@ -120,6 +129,10 @@
      * {@link #updateKeyphraseSoundModel}.
      * If the active voice interaction service changes from the current user, all requests will be
      * rejected, and any registered models will be unregistered.
+     * Caller must either be the active voice interaction service via
+     * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model
+     * enrollment application detected by
+     * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}.
      *
      * @param keyphraseId The unique identifier for the keyphrase.
      * @param locale The locale language tag supported by the desired model.
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/SchedulesProvider/res/values/config.xml b/packages/SettingsLib/SchedulesProvider/res/values/config.xml
new file mode 100644
index 0000000..48f3e3e
--- /dev/null
+++ b/packages/SettingsLib/SchedulesProvider/res/values/config.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<resources>
+    <!-- Package name for the caller of the Schedules provider. -->
+    <string name="config_schedules_provider_caller_package" translatable="false">com.android.settings</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
index 7d2b8e2..26bcd54 100644
--- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
@@ -24,9 +24,9 @@
 import androidx.annotation.NonNull;
 
 /**
- * This is a schedule data item. It contains the schedule title text, the summary text which
- * displays on the summary of the Settings preference and an {@link Intent}. Intent is able to
- * launch the editing page of the schedule data when user clicks this item (preference).
+ * Schedule data item containing the schedule title text, the summary text which is displayed on the
+ * summary of the Settings preference and an {@link Intent} which Settings will launch when the
+ * user clicks on the preference.
  */
 public class ScheduleInfo implements Parcelable {
     private static final String TAG = "ScheduleInfo";
@@ -40,7 +40,7 @@
         mIntent = builder.mIntent;
     }
 
-    protected ScheduleInfo(Parcel in) {
+    private ScheduleInfo(Parcel in) {
         mTitle = in.readString();
         mSummary = in.readString();
         mIntent = in.readParcelable(Intent.class.getClassLoader());
@@ -48,8 +48,6 @@
 
     /**
      * Returns the title text.
-     *
-     * @return The title.
      */
     public String getTitle() {
         return mTitle;
@@ -57,15 +55,14 @@
 
     /**
      * Returns the summary text.
-     *
-     * @return The summary.
      */
     public String getSummary() {
         return mSummary;
     }
 
     /**
-     * Returns an {@link Intent}.
+     * Returns an {@link Intent} which Settings will launch when the user clicks on a schedule
+     * preference.
      */
     public Intent getIntent() {
         return mIntent;
@@ -107,19 +104,15 @@
     @NonNull
     @Override
     public String toString() {
-        return "title : " + mTitle + " summary : " + mSummary + (mIntent == null
-                ? " and intent is null." : ".");
+        return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent;
     }
 
     /**
      * A simple builder for {@link ScheduleInfo}.
      */
     public static class Builder {
-        @NonNull
         private String mTitle;
-        @NonNull
         private String mSummary;
-        @NonNull
         private Intent mIntent;
 
         /**
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java
index a423e47..28d5f07 100644
--- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java
@@ -21,19 +21,18 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.stream.Collectors;
 
 /**
- * This provider is a bridge for client apps to provide the schedule data.
- * Client provider needs to implement their {@link #getScheduleInfoList()} and returns a list of
- * {@link ScheduleInfo}.
+ * A bridge for client apps to provide the schedule data. Client provider needs to implement
+ * {@link #getScheduleInfoList()} returning a list of {@link ScheduleInfo}.
  */
 public abstract class SchedulesProvider extends ContentProvider {
     public static final String METHOD_GENERATE_SCHEDULE_INFO_LIST = "generateScheduleInfoList";
@@ -46,9 +45,8 @@
     }
 
     @Override
-    public final Cursor query(
-            Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
         throw new UnsupportedOperationException("Query operation is not supported currently.");
     }
 
@@ -74,18 +72,24 @@
     }
 
     /**
-     * Return the list of the schedule information.
-     *
-     * @return a list of the {@link ScheduleInfo}.
+     * Returns the list of the schedule information.
      */
     public abstract ArrayList<ScheduleInfo> getScheduleInfoList();
 
     /**
-     * Returns a bundle which contains a list of {@link ScheduleInfo} and data types:
-     * scheduleInfoList : ArrayList<ScheduleInfo>
+     * Returns a bundle which contains a list of {@link ScheduleInfo}s:
+     *
+     * <ul>
+     *   <li>scheduleInfoList: ArrayList<ScheduleInfo>
+     * </ul>
      */
     @Override
     public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
+        if (!TextUtils.equals(getCallingPackage(),
+                getContext().getText(R.string.config_schedules_provider_caller_package))) {
+            return null;
+        }
+
         final Bundle bundle = new Bundle();
         if (METHOD_GENERATE_SCHEDULE_INFO_LIST.equals(method)) {
             final ArrayList<ScheduleInfo> scheduleInfoList = filterInvalidData(
@@ -98,36 +102,40 @@
     }
 
     /**
-     * To filter the invalid schedule info.
+     * Filters our invalid schedule infos from {@code schedulesInfoList}.
      *
-     * @param scheduleInfoList The list of the {@link ScheduleInfo}.
-     * @return The valid list of the {@link ScheduleInfo}.
+     * @return valid {@link SchedulesInfo}s if {@code schedulesInfoList} is not null. Otherwise,
+     * null.
      */
-    private ArrayList<ScheduleInfo> filterInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
+    @Nullable
+    private ArrayList<ScheduleInfo> filterInvalidData(
+            @Nullable ArrayList<ScheduleInfo> scheduleInfoList) {
         if (scheduleInfoList == null) {
             Log.d(TAG, "package : " + getContext().getPackageName() + " has no scheduling data.");
             return null;
         }
         // Dump invalid data in debug mode.
         if (SystemProperties.getInt("ro.debuggable", 0) == 1) {
-            new Thread(() -> {
-                dumpInvalidData(scheduleInfoList);
-            }).start();
+            dumpInvalidData(scheduleInfoList);
         }
-        final List<ScheduleInfo> filteredList = scheduleInfoList
+        return scheduleInfoList
                 .stream()
-                .filter(scheduleInfo -> scheduleInfo.isValid())
-                .collect(Collectors.toList());
-
-        return new ArrayList<>(filteredList);
+                .filter(ScheduleInfo::isValid)
+                .collect(Collectors.toCollection(ArrayList::new));
     }
 
     private void dumpInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
-        Log.d(TAG, "package : " + getContext().getPackageName()
-                + " provided some scheduling data are invalid.");
-        scheduleInfoList
+        final boolean hasInvalidData = scheduleInfoList
                 .stream()
-                .filter(scheduleInfo -> !scheduleInfo.isValid())
-                .forEach(scheduleInfo -> Log.d(TAG, scheduleInfo.toString()));
+                .anyMatch(scheduleInfo -> !scheduleInfo.isValid());
+
+        if (hasInvalidData) {
+            Log.w(TAG, "package : " + getContext().getPackageName()
+                    + " provided some scheduling data that are invalid.");
+            scheduleInfoList
+                    .stream()
+                    .filter(scheduleInfo -> !scheduleInfo.isValid())
+                    .forEach(scheduleInfo -> Log.w(TAG, scheduleInfo.toString()));
+        }
     }
 }
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/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index f69e4f5..3ae9e1e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -15,9 +15,15 @@
  */
 package com.android.settingslib.media;
 
-import static android.media.MediaRoute2Info.DEVICE_TYPE_BLUETOOTH;
-import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV;
-import static android.media.MediaRoute2Info.DEVICE_TYPE_UNKNOWN;
+import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
+import static android.media.MediaRoute2Info.TYPE_GROUP;
+import static android.media.MediaRoute2Info.TYPE_HEARING_AID;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
+import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
+import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
+import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
 
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
@@ -165,6 +171,26 @@
     }
 
     /**
+     * Release session to stop playing media on MediaDevice.
+     */
+    boolean releaseSession() {
+        if (TextUtils.isEmpty(mPackageName)) {
+            Log.w(TAG, "releaseSession() package name is null or empty!");
+            return false;
+        }
+
+        final RoutingSessionInfo info = getRoutingSessionInfo();
+        if (info != null) {
+            mRouterManager.getControllerForSession(info).release();
+            return true;
+        }
+
+        Log.w(TAG, "releaseSession() Ignoring release session : " + mPackageName);
+
+        return false;
+    }
+
+    /**
      * Get the MediaDevice list that can be added to current media.
      *
      * @return list of MediaDevice
@@ -298,7 +324,9 @@
 
     private void buildAllRoutes() {
         for (MediaRoute2Info route : mRouterManager.getAllRoutes()) {
-            addMediaDevice(route);
+            if (route.isSystemRoute()) {
+                addMediaDevice(route);
+            }
         }
     }
 
@@ -309,27 +337,29 @@
     }
 
     private void addMediaDevice(MediaRoute2Info route) {
-        final int deviceType = route.getDeviceType();
+        final int deviceType = route.getType();
         MediaDevice mediaDevice = null;
         switch (deviceType) {
-            case DEVICE_TYPE_UNKNOWN:
+            case TYPE_UNKNOWN:
+            case TYPE_REMOTE_TV:
+            case TYPE_REMOTE_SPEAKER:
+            case TYPE_GROUP:
                 //TODO(b/148765806): use correct device type once api is ready.
-                final String defaultRoute = "DEFAULT_ROUTE";
-                if (TextUtils.equals(defaultRoute, route.getOriginalId())) {
-                    mediaDevice =
-                            new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName);
-                } else {
-                    mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
-                            mPackageName);
-                    if (!TextUtils.isEmpty(mPackageName)
-                            && TextUtils.equals(route.getClientPackageName(), mPackageName)) {
-                        mCurrentConnectedDevice = mediaDevice;
-                    }
+                mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
+                        mPackageName);
+                if (!TextUtils.isEmpty(mPackageName)
+                        && TextUtils.equals(route.getClientPackageName(), mPackageName)) {
+                    mCurrentConnectedDevice = mediaDevice;
                 }
                 break;
-            case DEVICE_TYPE_REMOTE_TV:
+            case TYPE_BUILTIN_SPEAKER:
+            case TYPE_WIRED_HEADSET:
+            case TYPE_WIRED_HEADPHONES:
+                mediaDevice =
+                        new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName);
                 break;
-            case DEVICE_TYPE_BLUETOOTH:
+            case TYPE_HEARING_AID:
+            case TYPE_BLUETOOTH_A2DP:
                 final BluetoothDevice device =
                         BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getOriginalId());
                 final CachedBluetoothDevice cachedDevice =
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 617da6e..c70811f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -282,6 +282,13 @@
     }
 
     /**
+     * Release session to stop playing media on MediaDevice.
+     */
+    public boolean releaseSession() {
+        return mInfoMediaManager.releaseSession();
+    }
+
+    /**
      * Get the MediaDevice list that has been selected to current media.
      *
      * @return list of MediaDevice
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index d233649..0e6a60b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -68,7 +68,8 @@
             for (int reason = 0; reason <= getMaxNetworkSelectionDisableReason(); reason++) {
                 if (networkStatus.getDisableReasonCounter(reason) != 0) {
                     summary.append(" ")
-                            .append(NetworkSelectionStatus.getNetworkDisableReasonString(reason))
+                            .append(NetworkSelectionStatus
+                                    .getNetworkSelectionDisableReasonString(reason))
                             .append("=")
                             .append(networkStatus.getDisableReasonCounter(reason));
                 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 9668629..edb121b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -96,6 +96,7 @@
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
         when(info.getId()).thenReturn(TEST_ID);
         when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.isSystemRoute()).thenReturn(true);
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
@@ -166,6 +167,7 @@
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
         when(info.getId()).thenReturn(TEST_ID);
         when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.isSystemRoute()).thenReturn(true);
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
@@ -221,6 +223,7 @@
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
         when(info.getId()).thenReturn(TEST_ID);
         when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.isSystemRoute()).thenReturn(true);
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
@@ -438,4 +441,23 @@
 
         assertThat(mInfoMediaManager.getSessionVolume()).isEqualTo(-1);
     }
+
+    @Test
+    public void releaseSession_packageNameIsNull_returnFalse() {
+        mInfoMediaManager.mPackageName = null;
+
+        assertThat(mInfoMediaManager.releaseSession()).isFalse();
+    }
+
+    @Test
+    public void releaseSession_removeSuccessfully_returnTrue() {
+        final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+        final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+        routingSessionInfos.add(info);
+
+        mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+        assertThat(mInfoMediaManager.releaseSession()).isTrue();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
new file mode 100644
index 0000000..5ec89ed
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.settingslib.schedulesprovider;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ScheduleInfoTest {
+    private static final String TEST_TITLE = "Night Light";
+    private static final String TEST_SUMMARY = "Night Light summary";
+    private static final String TEST_EMPTY_SUMMARY = "";
+
+    @Test
+    public void builder_usedValidArguments_isValid() {
+        final Intent intent = createTestIntent();
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+
+        assertThat(info).isNotNull();
+        assertThat(info.isValid()).isTrue();
+    }
+
+    @Test
+    public void builder_useEmptySummary_isInvalid() {
+        final Intent intent = createTestIntent();
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent);
+
+        assertThat(info).isNotNull();
+        assertThat(info.isValid()).isFalse();
+    }
+
+    @Test
+    public void builder_intentIsNull_isInvalid() {
+        final ScheduleInfo info = new ScheduleInfo.Builder()
+                .setTitle(TEST_TITLE)
+                .setSummary(TEST_SUMMARY)
+                .build();
+
+        assertThat(info).isNotNull();
+        assertThat(info.isValid()).isFalse();
+    }
+
+    @Test
+    public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() {
+        final Intent intent = createTestIntent();
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+
+        assertThat(info.getTitle()).isEqualTo(TEST_TITLE);
+    }
+
+    @Test
+    public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() {
+        final Intent intent = createTestIntent();
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+
+        assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY);
+    }
+
+    @Test
+    public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() {
+        final Intent intent = createTestIntent();
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+
+        assertThat(info.getIntent()).isEqualTo(intent);
+    }
+
+    private static Intent createTestIntent() {
+        return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+                Intent.CATEGORY_DEFAULT);
+    }
+
+    private static ScheduleInfo createTestScheduleInfo(String title, String summary,
+            Intent intent) {
+        return new ScheduleInfo.Builder()
+                .setTitle(title)
+                .setSummary(summary)
+                .setIntent(intent)
+                .build();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
new file mode 100644
index 0000000..eb2e8e0
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.settingslib.schedulesprovider;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+
+@RunWith(RobolectricTestRunner.class)
+public class SchedulesProviderTest {
+    private static final String INVALID_PACKAGE = "com.android.sunny";
+    private static final String VALID_PACKAGE = "com.android.settings";
+    private static final String INVALID_METHOD = "queryTestData";
+    private TestSchedulesProvider mProvider;
+
+    @Before
+    public void setUp() {
+        mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class);
+        shadowOf(mProvider).setCallingPackage(VALID_PACKAGE);
+        mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo());
+    }
+
+    @Test
+    public void call_invalidCallingPkg_returnNull() {
+        shadowOf(mProvider).setCallingPackage(INVALID_PACKAGE);
+
+        final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
+                null /* arg */, null /* extras */);
+
+        assertThat(bundle).isNull();
+    }
+
+    @Test
+    public void call_invalidMethod_returnBundleWithoutScheduleInfoData() {
+        final Bundle bundle = mProvider.call(INVALID_METHOD, null /* arg */, null /* extras */);
+
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isFalse();
+    }
+
+    @Test
+    public void call_validMethod_returnScheduleInfoData() {
+        final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
+                null /* arg */, null /* extras */);
+
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
+        final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
+                SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
+        assertThat(infos).hasSize(1);
+    }
+
+    @Test
+    public void call_addTwoValidData_returnScheduleInfoData() {
+        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos());
+        final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
+                null /* arg */, null /* extras */);
+
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
+        final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
+                SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
+        assertThat(infos).hasSize(2);
+    }
+
+    @Test
+    public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() {
+        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo());
+        final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
+                null /* arg */, null /* extras */);
+
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
+        final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
+                SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
+        assertThat(infos).hasSize(2);
+    }
+
+    private static class TestSchedulesProvider extends SchedulesProvider {
+        private ArrayList<ScheduleInfo> mScheduleInfos = new ArrayList<>();
+
+        @Override
+        public ArrayList<ScheduleInfo> getScheduleInfoList() {
+            return mScheduleInfos;
+        }
+
+        void setScheduleInfos(ArrayList<ScheduleInfo> scheduleInfos) {
+            mScheduleInfos = scheduleInfos;
+        }
+
+        private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() {
+            final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
+            final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            final ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
+                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            scheduleInfos.add(info);
+
+            return scheduleInfos;
+        }
+
+        private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() {
+            final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
+            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
+                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            scheduleInfos.add(info);
+
+            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
+                    "Display summary").setIntent(intent).build();
+            scheduleInfos.add(info);
+
+            return scheduleInfos;
+        }
+
+        private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() {
+            final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
+            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
+                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            scheduleInfos.add(info);
+
+            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
+                    "Display summary").setIntent(intent).build();
+            scheduleInfos.add(info);
+
+            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
+                    Intent.CATEGORY_DEFAULT);
+            info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent(
+                    intent).build();
+            scheduleInfos.add(info);
+
+            return scheduleInfos;
+        }
+    }
+}
diff --git a/packages/StatementService/AndroidManifest.xml b/packages/StatementService/AndroidManifest.xml
index d79d900..b00c37f 100644
--- a/packages/StatementService/AndroidManifest.xml
+++ b/packages/StatementService/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
 
     <application
             android:label="@string/service_name"
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/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 0b74a11a..a76f961 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -32,10 +32,10 @@
         android:alpha="0"/>
     <HorizontalScrollView
         android:id="@+id/global_screenshot_actions_container"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center"
-        android:elevation="3dp"
+        android:layout_gravity="bottom|left"
+        android:elevation="1dp"
         android:fillViewport="true"
         android:layout_marginHorizontal="@dimen/screenshot_action_container_margin_horizontal"
         android:gravity="center"
@@ -63,7 +63,7 @@
         android:id="@+id/global_screenshot_dismiss_button"
         android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
         android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
-        android:elevation="9dp"
+        android:elevation="7dp"
         android:visibility="gone">
         <ImageView
             android:layout_width="match_parent"
@@ -76,7 +76,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:src="@android:color/white"
-        android:elevation="8dp"
+        android:elevation="@dimen/screenshot_preview_elevation"
         android:visibility="gone"/>
     <com.android.systemui.screenshot.ScreenshotSelectorView
         android:id="@+id/global_screenshot_selector"
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index 79867a16b..6b94bef 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -19,7 +19,7 @@
               android:id="@+id/global_screenshot_action_chip"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
-              android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal"
+              android:layout_marginRight="@dimen/screenshot_action_chip_margin_right"
               android:layout_gravity="center"
               android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
               android:background="@drawable/action_chip_background"
@@ -35,7 +35,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end"
+        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
         android:textSize="@dimen/screenshot_action_chip_text_size"
-        android:textStyle="bold"
         android:textColor="@color/global_screenshot_button_text"/>
 </com.android.systemui.screenshot.ScreenshotActionChip>
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/config.xml b/packages/SystemUI/res/values/config.xml
index a49aedf..27ffcee 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,7 +471,7 @@
     <!-- 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 -->
+    <!-- Allow 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. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9caaa9f..12b9254 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -305,7 +305,7 @@
     <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen>
     <dimen name="global_screenshot_bg_padding">20dp</dimen>
     <dimen name="global_screenshot_x_scale">80dp</dimen>
-    <dimen name="screenshot_preview_elevation">8dp</dimen>
+    <dimen name="screenshot_preview_elevation">6dp</dimen>
     <dimen name="screenshot_offset_y">48dp</dimen>
     <dimen name="screenshot_offset_x">16dp</dimen>
     <dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen>
@@ -314,13 +314,13 @@
     <dimen name="screenshot_action_container_corner_radius">10dp</dimen>
     <dimen name="screenshot_action_container_padding_vertical">10dp</dimen>
     <dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
-    <dimen name="screenshot_action_container_padding_left">100dp</dimen>
+    <dimen name="screenshot_action_container_padding_left">96dp</dimen>
     <dimen name="screenshot_action_container_padding_right">8dp</dimen>
     <!-- Radius of the chip background on global screenshot actions -->
     <dimen name="screenshot_button_corner_radius">20dp</dimen>
-    <dimen name="screenshot_action_chip_margin_horizontal">4dp</dimen>
-    <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen>
-    <dimen name="screenshot_action_chip_icon_size">20dp</dimen>
+    <dimen name="screenshot_action_chip_margin_right">8dp</dimen>
+    <dimen name="screenshot_action_chip_padding_vertical">7dp</dimen>
+    <dimen name="screenshot_action_chip_icon_size">18dp</dimen>
     <dimen name="screenshot_action_chip_padding_start">8dp</dimen>
     <!-- Padding between icon and text -->
     <dimen name="screenshot_action_chip_padding_middle">8dp</dimen>
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/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/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 6ce6353..0f896c4 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -99,7 +99,8 @@
     private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
 
     private DisplayManager mDisplayManager;
-    private boolean mIsRegistered;
+    @VisibleForTesting
+    protected boolean mIsRegistered;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final Handler mMainHandler;
     private final TunerService mTunerService;
@@ -168,7 +169,6 @@
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         updateRoundedCornerRadii();
         setupDecorations();
-
         mDisplayListener = new DisplayManager.DisplayListener() {
             @Override
             public void onDisplayAdded(int displayId) {
@@ -230,7 +230,10 @@
             removeAllOverlays();
         }
 
-        if (hasOverlays() && !mIsRegistered) {
+        if (hasOverlays()) {
+            if (mIsRegistered) {
+                return;
+            }
             DisplayMetrics metrics = new DisplayMetrics();
             mDisplayManager.getDisplay(DEFAULT_DISPLAY).getMetrics(metrics);
             mDensity = metrics.density;
@@ -271,7 +274,8 @@
         return mContext.getDisplay().getCutout();
     }
 
-    private boolean hasOverlays() {
+    @VisibleForTesting
+    boolean hasOverlays() {
         if (mOverlays == null) {
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 20b3386..2873811 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -73,9 +73,6 @@
 
     private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
 
-    private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
-    private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
-
     /**
      * When true, if a notification has the information necessary to bubble (i.e. valid
      * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
@@ -131,16 +128,6 @@
     }
 
     /**
-     * When true, show a menu when a bubble is long-pressed, which will allow the user to take
-     * actions on that bubble.
-     */
-    static boolean allowBubbleOverflow(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                ALLOW_BUBBLE_OVERFLOW,
-                ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0;
-    }
-
-    /**
      * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
      * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
      * the notification has necessary info for BubbleMetadata.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 072c20c..df8e394 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -520,9 +520,6 @@
     }
 
     private void setUpOverflow() {
-        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
-            return;
-        }
         int overflowBtnIndex = 0;
         if (mBubbleOverflow == null) {
             mBubbleOverflow = new BubbleOverflow(mContext);
@@ -733,8 +730,7 @@
     @Nullable
     Bubble getExpandedBubble() {
         if (mExpandedBubble == null
-                || (BubbleExperimentConfig.allowBubbleOverflow(mContext)
-                    && mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
+                || (mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
                     && mExpandedBubble.getKey() == BubbleOverflow.KEY)) {
             return null;
         }
@@ -785,9 +781,6 @@
     }
 
     private void updateOverflowBtnVisibility(boolean apply) {
-        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
-            return;
-        }
         if (mIsExpanded) {
             if (DEBUG_BUBBLE_STACK_VIEW) {
                 Log.d(TAG, "Show overflow button.");
@@ -911,8 +904,7 @@
         float y = event.getRawY();
         if (mIsExpanded) {
             if (isIntersecting(mBubbleContainer, x, y)) {
-                if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
-                        && isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
+                if (isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
                     return mBubbleOverflow.getBtn();
                 }
                 // Could be tapping or dragging a bubble while expanded
@@ -1645,11 +1637,8 @@
      * @return the number of bubbles in the stack view.
      */
     public int getBubbleCount() {
-        if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
-            // Subtract 1 for the overflow button which is always in the bubble container.
-            return mBubbleContainer.getChildCount() - 1;
-        }
-        return mBubbleContainer.getChildCount();
+        // Subtract 1 for the overflow button that is always in the bubble container.
+        return mBubbleContainer.getChildCount() - 1;
     }
 
     /**
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..2c01449 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/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d688f0a..c129035 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -96,6 +96,7 @@
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.InjectionInflationController;
 
 import java.io.FileDescriptor;
@@ -378,6 +379,17 @@
     private IKeyguardDrawnCallback mDrawnCallback;
     private CharSequence mCustomMessage;
 
+    private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+            @Override
+            public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) {
+                    mShowHomeOverLockscreen = properties.getBoolean(
+                            NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */);
+                }
+            }
+    };
+
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -692,6 +704,8 @@
         }
     };
 
+    private DeviceConfigProxy mDeviceConfig;
+
     /**
      * Injected constructor. See {@link KeyguardModule}.
      */
@@ -705,7 +719,8 @@
             DismissCallbackRegistry dismissCallbackRegistry,
             KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager,
             @UiBackground Executor uiBgExecutor, PowerManager powerManager,
-            TrustManager trustManager) {
+            TrustManager trustManager,
+            DeviceConfigProxy deviceConfig) {
         super(context);
         mFalsingManager = falsingManager;
         mLockPatternUtils = lockPatternUtils;
@@ -718,20 +733,15 @@
         mPM = powerManager;
         mTrustManager = trustManager;
         dumpManager.registerDumpable(getClass().getName(), this);
-        mShowHomeOverLockscreen = DeviceConfig.getBoolean(
+        mDeviceConfig = deviceConfig;
+        mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
                 /* defaultValue = */ true);
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post,
-                new DeviceConfig.OnPropertiesChangedListener() {
-                    @Override
-                    public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                        if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) {
-                            mShowHomeOverLockscreen = properties.getBoolean(
-                                    NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */);
-                        }
-                    }
-                });
+        mDeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                mHandler::post,
+                mOnPropertiesChangedListener);
     }
 
     public void userActivity() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7af360..367f464 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.concurrent.Executor;
 
@@ -62,7 +63,8 @@
             DumpManager dumpManager,
             PowerManager powerManager,
             TrustManager trustManager,
-            @UiBackground Executor uiBgExecutor) {
+            @UiBackground Executor uiBgExecutor,
+            DeviceConfigProxy deviceConfig) {
         return new KeyguardViewMediator(
                 context,
                 falsingManager,
@@ -75,6 +77,7 @@
                 dumpManager,
                 uiBgExecutor,
                 powerManager,
-                trustManager);
+                trustManager,
+                deviceConfig);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index e98dec0..7b96268 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -48,6 +48,7 @@
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.wm.DisplayChangeController;
 import com.android.systemui.wm.DisplayController;
@@ -204,7 +205,8 @@
     @Inject
     public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
             DisplayController displayController,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            DeviceConfigProxy deviceConfig) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
 
@@ -225,7 +227,7 @@
                 mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager,
                 mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
-                floatingContentCoordinator);
+                floatingContentCoordinator, deviceConfig);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
         displayController.addDisplayChangingController(mRotationController);
@@ -339,7 +341,10 @@
 
     private void updateMovementBounds(Rect animatingBounds, boolean fromImeAdjustment,
             boolean fromShelfAdjustment) {
-        // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
+        mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo);
+        // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before
+        // passing to mTouchHandler, mTouchHandler would rely on the bounds calculated by
+        // mPipBoundsHandler with up-to-dated information
         mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
                 animatingBounds, mTmpDisplayInfo);
         mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 91f539c..980d18b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -411,11 +411,9 @@
     }
 
     private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
-        if (offset == 0) {
-            return;
-        }
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = originalBounds;
+        // offset would be zero if triggered from screen rotation.
         args.argi1 = offset;
         args.argi2 = duration;
         mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 9fb6234..389793e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -41,6 +41,7 @@
 import com.android.internal.policy.TaskResizingAlgorithm;
 import com.android.systemui.R;
 import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.concurrent.Executor;
 
@@ -77,7 +78,8 @@
     private int mCtrlType;
 
     public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
-            PipTouchHandler pipTouchHandler, PipMotionHelper motionHelper) {
+            PipTouchHandler pipTouchHandler, PipMotionHelper motionHelper,
+            DeviceConfigProxy deviceConfig) {
         final Resources res = context.getResources();
         context.getDisplay().getMetrics(mDisplayMetrics);
         mDisplayId = context.getDisplayId();
@@ -93,7 +95,7 @@
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_USER_RESIZE,
                 /* defaultValue = */ false);
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
+        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
                 new DeviceConfig.OnPropertiesChangedListener() {
                     @Override
                     public void onPropertiesChanged(DeviceConfig.Properties properties) {
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 3b855db..3f73d01 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -48,6 +48,7 @@
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.FloatingContentCoordinator;
 
 import java.io.PrintWriter;
@@ -164,7 +165,8 @@
             InputConsumerController inputConsumerController,
             PipBoundsHandler pipBoundsHandler,
             PipTaskOrganizer pipTaskOrganizer,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            DeviceConfigProxy deviceConfig) {
         // Initialize the Pip input consumer
         mContext = context;
         mActivityManager = activityManager;
@@ -179,7 +181,8 @@
         mMotionHelper = new PipMotionHelper(mContext, activityTaskManager, pipTaskOrganizer,
                 mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator);
         mPipResizeGestureHandler =
-                new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper);
+                new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper,
+                        deviceConfig);
         mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
                 () -> mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
                         mMovementBounds, true /* allowMenuTimeout */, willResizeMenu()));
@@ -266,6 +269,10 @@
     public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds,
             boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) {
         final int bottomOffset = mIsImeShowing ? mImeHeight : 0;
+        final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation);
+        if (fromDisplayRotationChanged) {
+            mTouchState.reset();
+        }
 
         // Re-calculate the expanded bounds
         mNormalBounds = normalBounds;
@@ -293,7 +300,7 @@
 
         // If this is from an IME or shelf adjustment, then we should move the PiP so that it is not
         // occluded by the IME or shelf.
-        if (fromImeAdjustment || fromShelfAdjustment) {
+        if (fromImeAdjustment || fromShelfAdjustment || fromDisplayRotationChanged) {
             if (mTouchState.isUserInteracting()) {
                 // Defer the update of the current movement bounds until after the user finishes
                 // touching the screen
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/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 626f298..390ac09 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -63,7 +63,7 @@
 /**
  * A service which records the device screen and optionally microphone input.
  */
-public class RecordingService extends Service {
+public class RecordingService extends Service implements MediaRecorder.OnInfoListener {
     public static final int REQUEST_CODE = 2;
 
     private static final int NOTIFICATION_ID = 1;
@@ -85,6 +85,8 @@
     private static final int VIDEO_FRAME_RATE = 30;
     private static final int AUDIO_BIT_RATE = 16;
     private static final int AUDIO_SAMPLE_RATE = 44100;
+    private static final int MAX_DURATION_MS = 60 * 60 * 1000;
+    private static final long MAX_FILESIZE_BYTES = 5000000000L;
 
     private final RecordingController mController;
     private MediaProjection mMediaProjection;
@@ -250,6 +252,8 @@
             mMediaRecorder.setVideoSize(screenWidth, screenHeight);
             mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
             mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+            mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
+            mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
 
             // Set up audio
             if (mUseAudio) {
@@ -274,6 +278,7 @@
                     null,
                     null);
 
+            mMediaRecorder.setOnInfoListener(this);
             mMediaRecorder.start();
             mController.updateState(true);
         } catch (IOException e) {
@@ -454,4 +459,10 @@
         return new Intent(context, RecordingService.class).setAction(ACTION_DELETE)
                 .putExtra(EXTRA_PATH, path);
     }
+
+    @Override
+    public void onInfo(MediaRecorder mr, int what, int extra) {
+        Log.d(TAG, "Media recorder info: " + what);
+        onStartCommand(getStopIntent(this), 0, 0);
+    }
 }
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/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index f8db922..cdb2c53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -65,6 +65,7 @@
 import com.android.systemui.statusbar.phone.ScrimState;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -183,7 +184,8 @@
             NotificationEntryManager notificationEntryManager,
             MediaArtworkProcessor mediaArtworkProcessor,
             KeyguardBypassController keyguardBypassController,
-            @Main Executor mainExecutor) {
+            @Main Executor mainExecutor,
+            DeviceConfigProxy deviceConfig) {
         mContext = context;
         mMediaArtworkProcessor = mediaArtworkProcessor;
         mKeyguardBypassController = keyguardBypassController;
@@ -221,7 +223,7 @@
                 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
 
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                 mContext.getMainExecutor(),
                 mPropertiesChangedListener);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 7e70c20..fe2f1f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.StatusBarModule;
+import com.android.systemui.statusbar.notification.DynamicChildBindController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -59,11 +60,12 @@
 
     private final Handler mHandler;
 
-    //TODO: change this top <Entry, List<Entry>>?
-    private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>>
-            mTmpChildOrderMap = new HashMap<>();
+    /** Re-usable map of notifications to their sorted children.*/
+    private final HashMap<NotificationEntry, List<NotificationEntry>> mTmpChildOrderMap =
+            new HashMap<>();
 
     // Dependencies:
+    private final DynamicChildBindController mDynamicChildBindController;
     protected final NotificationLockscreenUserManager mLockscreenUserManager;
     protected final NotificationGroupManager mGroupManager;
     protected final VisualStabilityManager mVisualStabilityManager;
@@ -105,7 +107,8 @@
             KeyguardBypassController bypassController,
             BubbleController bubbleController,
             DynamicPrivacyController privacyController,
-            ForegroundServiceSectionController fgsSectionController) {
+            ForegroundServiceSectionController fgsSectionController,
+            DynamicChildBindController dynamicChildBindController) {
         mContext = context;
         mHandler = mainHandler;
         mLockscreenUserManager = notificationLockscreenUserManager;
@@ -121,6 +124,7 @@
         mBubbleController = bubbleController;
         mDynamicPrivacyController = privacyController;
         privacyController.addListener(this);
+        mDynamicChildBindController = dynamicChildBindController;
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -175,13 +179,12 @@
             ent.getRow().setNeedsRedaction(needsRedaction);
             if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) {
                 NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn());
-                List<ExpandableNotificationRow> orderedChildren =
-                        mTmpChildOrderMap.get(summary.getRow());
+                List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(summary);
                 if (orderedChildren == null) {
                     orderedChildren = new ArrayList<>();
-                    mTmpChildOrderMap.put(summary.getRow(), orderedChildren);
+                    mTmpChildOrderMap.put(summary, orderedChildren);
                 }
-                orderedChildren.add(ent.getRow());
+                orderedChildren.add(ent);
             } else {
                 toShow.add(ent.getRow());
             }
@@ -260,6 +263,7 @@
 
         }
 
+        mDynamicChildBindController.updateChildContentViews(mTmpChildOrderMap);
         mVisualStabilityManager.onReorderingFinished();
         // clear the map again for the next usage
         mTmpChildOrderMap.clear();
@@ -274,6 +278,7 @@
     private void addNotificationChildrenAndSort() {
         // Let's now add all notification children which are missing
         boolean orderChanged = false;
+        ArrayList<ExpandableNotificationRow> orderedRows = new ArrayList<>();
         for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
             View view = mListContainer.getContainerChildAt(i);
             if (!(view instanceof ExpandableNotificationRow)) {
@@ -283,11 +288,11 @@
 
             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
-            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+            List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent.getEntry());
 
             for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
                     childIndex++) {
-                ExpandableNotificationRow childView = orderedChildren.get(childIndex);
+                ExpandableNotificationRow childView = orderedChildren.get(childIndex).getRow();
                 if (children == null || !children.contains(childView)) {
                     if (childView.getParent() != null) {
                         Log.wtf(TAG, "trying to add a notification child that already has " +
@@ -300,11 +305,13 @@
                     parent.addChildNotification(childView, childIndex);
                     mListContainer.notifyGroupChildAdded(childView);
                 }
+                orderedRows.add(childView);
             }
 
             // Finally after removing and adding has been performed we can apply the order.
-            orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager,
+            orderChanged |= parent.applyChildOrder(orderedRows, mVisualStabilityManager,
                     mEntryManager);
+            orderedRows.clear();
         }
         if (orderChanged) {
             mListContainer.generateChildOrderChangedEvent();
@@ -323,13 +330,13 @@
 
             ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
             List<ExpandableNotificationRow> children = parent.getNotificationChildren();
-            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+            List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent.getEntry());
 
             if (children != null) {
                 toRemove.clear();
                 for (ExpandableNotificationRow childRow : children) {
                     if ((orderedChildren == null
-                            || !orderedChildren.contains(childRow))
+                            || !orderedChildren.contains(childRow.getEntry()))
                             && !childRow.keepInParent()) {
                         toRemove.add(childRow);
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index cd5bb77..4c99a90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.DynamicChildBindController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -42,6 +43,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.tracing.ProtoTracer;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.concurrent.Executor;
 
@@ -91,7 +93,8 @@
             NotificationEntryManager notificationEntryManager,
             MediaArtworkProcessor mediaArtworkProcessor,
             KeyguardBypassController keyguardBypassController,
-            @Main Executor mainExecutor) {
+            @Main Executor mainExecutor,
+            DeviceConfigProxy deviceConfigProxy) {
         return new NotificationMediaManager(
                 context,
                 statusBarLazy,
@@ -99,7 +102,8 @@
                 notificationEntryManager,
                 mediaArtworkProcessor,
                 keyguardBypassController,
-                mainExecutor);
+                mainExecutor,
+                deviceConfigProxy);
     }
 
     /** */
@@ -135,7 +139,8 @@
             KeyguardBypassController bypassController,
             BubbleController bubbleController,
             DynamicPrivacyController privacyController,
-            ForegroundServiceSectionController fgsSectionController) {
+            ForegroundServiceSectionController fgsSectionController,
+            DynamicChildBindController dynamicChildBindController) {
         return new NotificationViewHierarchyManager(
                 context,
                 mainHandler,
@@ -147,7 +152,8 @@
                 bypassController,
                 bubbleController,
                 privacyController,
-                fgsSectionController);
+                fgsSectionController,
+                dynamicChildBindController);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java
new file mode 100644
index 0000000..059d6ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_EXPANDED;
+import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.RowContentBindParams;
+import com.android.systemui.statusbar.notification.row.RowContentBindStage;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Controller that binds/unbinds views content views on notification group children.
+ *
+ * We currently only show a limited number of notification children even if more exist, so we
+ * can save memory by freeing content views when they're not visible and binding them again when
+ * they get close to being visible.
+ *
+ * Eventually, when {@link NotifPipeline} takes over as the new notification pipeline, we'll have
+ * more control over which notifications even make it to inflation in the first place and be able
+ * to enforce this at an earlier stage at the level of the {@link ExpandableNotificationRow}, but
+ * for now, we're just doing it at the level of content views.
+ */
+public class DynamicChildBindController {
+    private final RowContentBindStage mStage;
+    private final int mChildBindCutoff;
+
+    @Inject
+    public DynamicChildBindController(RowContentBindStage stage) {
+        this(stage, CHILD_BIND_CUTOFF);
+    }
+
+    /**
+     * @param childBindCutoff the cutoff where we no longer bother having content views bound
+     */
+    DynamicChildBindController(
+            RowContentBindStage stage,
+            int childBindCutoff) {
+        mStage = stage;
+        mChildBindCutoff = childBindCutoff;
+    }
+
+    /**
+     * Update the child content views, unbinding content views on children that won't be visible
+     * and binding content views on children that will be visible eventually.
+     *
+     * @param groupNotifs map of notification summaries to their children
+     */
+    public void updateChildContentViews(
+            Map<NotificationEntry, List<NotificationEntry>> groupNotifs) {
+        for (NotificationEntry entry : groupNotifs.keySet()) {
+            List<NotificationEntry> children = groupNotifs.get(entry);
+            for (int j = 0; j < children.size(); j++) {
+                NotificationEntry childEntry = children.get(j);
+                if (j >= mChildBindCutoff) {
+                    if (hasChildContent(childEntry)) {
+                        freeChildContent(childEntry);
+                    }
+                } else {
+                    if (!hasChildContent(childEntry)) {
+                        bindChildContent(childEntry);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean hasChildContent(NotificationEntry entry) {
+        ExpandableNotificationRow row = entry.getRow();
+        return row.getPrivateLayout().getContractedChild() != null
+                || row.getPrivateLayout().getExpandedChild() != null;
+    }
+
+    private void freeChildContent(NotificationEntry entry) {
+        RowContentBindParams params = mStage.getStageParams(entry);
+        params.freeContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+        params.freeContentViews(FLAG_CONTENT_VIEW_EXPANDED);
+        mStage.requestRebind(entry, null);
+    }
+
+    private void bindChildContent(NotificationEntry entry) {
+        RowContentBindParams params = mStage.getStageParams(entry);
+        params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+        params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
+        mStage.requestRebind(entry, null);
+    }
+
+    /**
+     * How big the buffer of extra views we keep around to be ready to show when we do need to
+     * dynamically inflate.
+     */
+    private static final int EXTRA_VIEW_BUFFER_COUNT = 1;
+
+    private static final int CHILD_BIND_CUTOFF =
+            NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT;
+}
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 004b56b..6d3f126 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
@@ -18,7 +18,10 @@
 
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
 
@@ -467,6 +470,14 @@
             }
         };
         switch (inflationFlag) {
+            case FLAG_CONTENT_VIEW_CONTRACTED:
+                getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED,
+                        freeViewRunnable);
+                break;
+            case FLAG_CONTENT_VIEW_EXPANDED:
+                getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_EXPANDED,
+                        freeViewRunnable);
+                break;
             case FLAG_CONTENT_VIEW_HEADS_UP:
                 getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
                         freeViewRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index e3ca283..6dd4ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 
 import android.annotation.NonNull;
@@ -191,6 +192,18 @@
     private void freeNotificationView(NotificationEntry entry, ExpandableNotificationRow row,
             @InflationFlag int inflateFlag) {
         switch (inflateFlag) {
+            case FLAG_CONTENT_VIEW_CONTRACTED:
+                if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) {
+                    row.getPrivateLayout().setContractedChild(null);
+                    mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED);
+                }
+                break;
+            case FLAG_CONTENT_VIEW_EXPANDED:
+                if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_EXPANDED)) {
+                    row.getPrivateLayout().setExpandedChild(null);
+                    mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED);
+                }
+                break;
             case FLAG_CONTENT_VIEW_HEADS_UP:
                 if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) {
                     row.getPrivateLayout().setHeadsUpChild(null);
@@ -204,8 +217,6 @@
                     mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC);
                 }
                 break;
-            case FLAG_CONTENT_VIEW_CONTRACTED:
-            case FLAG_CONTENT_VIEW_EXPANDED:
             default:
                 break;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index d1b9a87..27fd1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -71,7 +71,13 @@
     public static final int VISIBLE_TYPE_EXPANDED = 1;
     public static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
-    public static final int UNDEFINED = -1;
+    /**
+     * Used when there is no content on the view such as when we're a public layout but don't
+     * need to show.
+     */
+    private static final int VISIBLE_TYPE_NONE = -1;
+
+    private static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
 
@@ -99,7 +105,7 @@
     private HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
-    private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
+    private int mVisibleType = VISIBLE_TYPE_NONE;
     private boolean mAnimate;
     private boolean mIsHeadsUp;
     private boolean mLegacy;
@@ -141,7 +147,7 @@
     /** The visible type at the start of a touch driven transformation */
     private int mTransformationStartVisibleType;
     /** The visible type at the start of an animation driven transformation */
-    private int mAnimationStartVisibleType = UNDEFINED;
+    private int mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
     private boolean mUserExpanding;
     private int mSingleLineWidthIndention;
     private boolean mForceSelectNextLayout = true;
@@ -386,7 +392,7 @@
             mContractedChild = null;
             mContractedWrapper = null;
             if (mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED) {
-                mTransformationStartVisibleType = UNDEFINED;
+                mTransformationStartVisibleType = VISIBLE_TYPE_NONE;
             }
             return;
         }
@@ -434,7 +440,7 @@
             mExpandedChild = null;
             mExpandedWrapper = null;
             if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) {
-                mTransformationStartVisibleType = UNDEFINED;
+                mTransformationStartVisibleType = VISIBLE_TYPE_NONE;
             }
             if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
                 selectLayout(false /* animate */, true /* force */);
@@ -472,7 +478,7 @@
             mHeadsUpChild = null;
             mHeadsUpWrapper = null;
             if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) {
-                mTransformationStartVisibleType = UNDEFINED;
+                mTransformationStartVisibleType = VISIBLE_TYPE_NONE;
             }
             if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
                 selectLayout(false /* animate */, true /* force */);
@@ -597,7 +603,7 @@
         }
 
         // Size change of the expanded version
-        if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0
+        if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart != UNDEFINED
                 && mExpandedChild != null) {
             return Math.min(mContentHeightAtAnimationStart, getViewHeight(VISIBLE_TYPE_EXPANDED));
         }
@@ -607,10 +613,12 @@
             hint = getViewHeight(VISIBLE_TYPE_HEADSUP);
         } else if (mExpandedChild != null) {
             hint = getViewHeight(VISIBLE_TYPE_EXPANDED);
-        } else {
+        } else if (mContractedChild != null) {
             hint = getViewHeight(VISIBLE_TYPE_CONTRACTED)
                     + mContext.getResources().getDimensionPixelSize(
                             com.android.internal.R.dimen.notification_action_list_height);
+        } else {
+            hint = getMinHeight();
         }
 
         if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) {
@@ -646,7 +654,7 @@
         if (mForceSelectNextLayout) {
             forceUpdateVisibilities();
         }
-        if (mTransformationStartVisibleType != UNDEFINED
+        if (mTransformationStartVisibleType != VISIBLE_TYPE_NONE
                 && mVisibleType != mTransformationStartVisibleType
                 && getViewForVisibleType(mTransformationStartVisibleType) != null) {
             final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
@@ -823,7 +831,7 @@
         fireExpandedVisibleListenerIfVisible();
         // forceUpdateVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
-        mAnimationStartVisibleType = UNDEFINED;
+        mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
     }
 
     private void fireExpandedVisibleListenerIfVisible() {
@@ -898,7 +906,7 @@
         fireExpandedVisibleListenerIfVisible();
         // updateViewVisibilities cancels outstanding animations without updating the
         // mAnimationStartVisibleType. Do so here instead.
-        mAnimationStartVisibleType = UNDEFINED;
+        mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
     }
 
     private void updateViewVisibility(int visibleType, int type, View view,
@@ -924,7 +932,7 @@
                 if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
                     hiddenView.setVisible(false);
                 }
-                mAnimationStartVisibleType = UNDEFINED;
+                mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
             }
         });
         fireExpandedVisibleListenerIfVisible();
@@ -1041,8 +1049,10 @@
                     && (!mIsChildInGroup || isGroupExpanded()
                             || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
                 return VISIBLE_TYPE_CONTRACTED;
-            } else {
+            } else if (!noExpandedChild) {
                 return VISIBLE_TYPE_EXPANDED;
+            } else {
+                return VISIBLE_TYPE_NONE;
             }
         }
     }
@@ -1423,7 +1433,8 @@
         if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
             if ((!mIsHeadsUp && !mHeadsUpAnimatingAway)
                     || mHeadsUpChild == null || !mContainingNotification.canShowHeadsUp()) {
-                if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
+                if (mContractedChild == null
+                        || mExpandedChild.getHeight() <= mContractedChild.getHeight()) {
                     expandable = false;
                 }
             } else if (mExpandedChild.getHeight() <= mHeadsUpChild.getHeight()) {
@@ -1514,7 +1525,7 @@
         if (userExpanding) {
             mTransformationStartVisibleType = mVisibleType;
         } else {
-            mTransformationStartVisibleType = UNDEFINED;
+            mTransformationStartVisibleType = VISIBLE_TYPE_NONE;
             mVisibleType = calculateVisibleType();
             updateViewVisibilities(mVisibleType);
             updateBackgroundColor(false);
@@ -1558,6 +1569,7 @@
     }
 
     public void setContentHeightAnimating(boolean animating) {
+        //TODO: It's odd that this does nothing when animating is true
         if (!animating) {
             mContentHeightAtAnimationStart = UNDEFINED;
         }
@@ -1565,7 +1577,7 @@
 
     @VisibleForTesting
     boolean isAnimatingVisibleType() {
-        return mAnimationStartVisibleType != UNDEFINED;
+        return mAnimationStartVisibleType != VISIBLE_TYPE_NONE;
     }
 
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
@@ -1758,17 +1770,25 @@
     }
 
     public int getExpandHeight() {
-        int viewType = VISIBLE_TYPE_EXPANDED;
-        if (mExpandedChild == null) {
+        int viewType;
+        if (mExpandedChild != null) {
+            viewType = VISIBLE_TYPE_EXPANDED;
+        } else if (mContractedChild != null) {
             viewType = VISIBLE_TYPE_CONTRACTED;
+        } else {
+            return getMinHeight();
         }
         return getViewHeight(viewType) + getExtraRemoteInputHeight(mExpandedRemoteInput);
     }
 
     public int getHeadsUpHeight(boolean forceNoHeader) {
-        int viewType = VISIBLE_TYPE_HEADSUP;
-        if (mHeadsUpChild == null) {
+        int viewType;
+        if (mHeadsUpChild != null) {
+            viewType = VISIBLE_TYPE_HEADSUP;
+        } else if (mContractedChild != null) {
             viewType = VISIBLE_TYPE_CONTRACTED;
+        } else {
+            return getMinHeight();
         }
         // The headsUp remote input quickly switches to the expanded one, so lets also include that
         // one
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 75ceb0f..d7c88e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -53,8 +53,7 @@
     static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
     @VisibleForTesting
     static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
-    @VisibleForTesting
-    static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+    public static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
     private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
         private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
 
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/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 312c4ac..d29f4fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -31,14 +31,12 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.security.KeyChain;
-import android.security.KeyChain.KeyChainConnection;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
@@ -55,6 +53,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -85,7 +84,7 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
-    private final Handler mBgHandler;
+    private final Executor mBgExecutor;
 
     @GuardedBy("mCallbacks")
     private final ArrayList<SecurityControllerCallback> mCallbacks = new ArrayList<>();
@@ -101,16 +100,14 @@
     /**
      */
     @Inject
-    public SecurityControllerImpl(Context context, @Background Handler bgHandler,
-            BroadcastDispatcher broadcastDispatcher) {
-        this(context, bgHandler, broadcastDispatcher, null);
-    }
-
-    public SecurityControllerImpl(Context context, Handler bgHandler,
-            BroadcastDispatcher broadcastDispatcher, SecurityControllerCallback callback) {
+    public SecurityControllerImpl(
+            Context context,
+            @Background Handler bgHandler,
+            BroadcastDispatcher broadcastDispatcher,
+            @Background Executor bgExecutor
+    ) {
         super(broadcastDispatcher);
         mContext = context;
-        mBgHandler = bgHandler;
         mDevicePolicyManager = (DevicePolicyManager)
                 context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mConnectivityManager = (ConnectivityManager)
@@ -118,10 +115,8 @@
         mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
         mPackageManager = context.getPackageManager();
-        mUserManager = (UserManager)
-                context.getSystemService(Context.USER_SERVICE);
-
-        addCallback(callback);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mBgExecutor = bgExecutor;
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
@@ -305,7 +300,23 @@
     }
 
     private void refreshCACerts(int userId) {
-        new CACertLoader().execute(userId);
+        mBgExecutor.execute(() -> {
+            Pair<Integer, Boolean> idWithCert = null;
+            try (KeyChain.KeyChainConnection conn = KeyChain.bindAsUser(mContext,
+                    UserHandle.of(userId))) {
+                boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty());
+                idWithCert = new Pair<Integer, Boolean>(userId, hasCACerts);
+            } catch (RemoteException | InterruptedException | AssertionError e) {
+                Log.i(TAG, "failed to get CA certs", e);
+                idWithCert = new Pair<Integer, Boolean>(userId, null);
+            } finally {
+                if (DEBUG) Log.d(TAG, "Refreshing CA Certs " + idWithCert);
+                if (idWithCert != null && idWithCert.second != null) {
+                    mHasCACerts.put(idWithCert.first, idWithCert.second);
+                    fireCallbacks();
+                }
+            }
+        });
     }
 
     private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) {
@@ -408,28 +419,4 @@
             }
         }
     };
-
-    protected class CACertLoader extends AsyncTask<Integer, Void, Pair<Integer, Boolean> > {
-
-        @Override
-        protected Pair<Integer, Boolean> doInBackground(Integer... userId) {
-            try (KeyChainConnection conn = KeyChain.bindAsUser(mContext,
-                                                               UserHandle.of(userId[0]))) {
-                boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty());
-                return new Pair<Integer, Boolean>(userId[0], hasCACerts);
-            } catch (RemoteException | InterruptedException | AssertionError e) {
-                Log.i(TAG, "failed to get CA certs", e);
-                return new Pair<Integer, Boolean>(userId[0], null);
-            }
-        }
-
-        @Override
-        protected void onPostExecute(Pair<Integer, Boolean> result) {
-            if (DEBUG) Log.d(TAG, "onPostExecute " + result);
-            if (result.second != null) {
-                mHasCACerts.put(result.first, result.second);
-                fireCallbacks();
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index 86fe3008..311e8738 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -25,10 +25,10 @@
 import android.util.KeyValueListParser;
 import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.DeviceConfigProxy;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -62,10 +62,15 @@
 
     private final Handler mHandler;
     private final Context mContext;
+    private final DeviceConfigProxy mDeviceConfig;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
 
     @Inject
-    public SmartReplyConstants(@Main Handler handler, Context context) {
+    public SmartReplyConstants(
+            @Main Handler handler,
+            Context context,
+            DeviceConfigProxy deviceConfig
+    ) {
         mHandler = handler;
         mContext = context;
         final Resources resources = mContext.getResources();
@@ -86,31 +91,35 @@
         mDefaultOnClickInitDelay = resources.getInteger(
                 R.integer.config_smart_replies_in_notifications_onclick_init_delay);
 
+        mDeviceConfig = deviceConfig;
         registerDeviceConfigListener();
         updateConstants();
     }
 
     private void registerDeviceConfigListener() {
-        DeviceConfig.addOnPropertiesChangedListener(
+        mDeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 this::postToHandler,
-                (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
+                mOnPropertiesChangedListener);
     }
 
     private void postToHandler(Runnable r) {
         this.mHandler.post(r);
     }
 
-    @VisibleForTesting
-    void onDeviceConfigPropertiesChanged(String namespace) {
-        if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
-            Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: "
-                    + namespace);
-            return;
-        }
-
-        updateConstants();
-    }
+    private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                    if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
+                        Log.e(TAG,
+                                "Received update from DeviceConfig for unrelated namespace: "
+                                        + properties.getNamespace());
+                        return;
+                    }
+                    updateConstants();
+                }
+            };
 
     private void updateConstants() {
         synchronized (SmartReplyConstants.this) {
@@ -120,7 +129,7 @@
             mRequiresTargetingP = readDeviceConfigBooleanOrDefaultIfEmpty(
                     SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P,
                     mDefaultRequiresP);
-            mMaxSqueezeRemeasureAttempts = DeviceConfig.getInt(
+            mMaxSqueezeRemeasureAttempts = mDeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS,
                     mDefaultMaxSqueezeRemeasureAttempts);
@@ -130,24 +139,24 @@
             mShowInHeadsUp = readDeviceConfigBooleanOrDefaultIfEmpty(
                     SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP,
                     mDefaultShowInHeadsUp);
-            mMinNumSystemGeneratedReplies = DeviceConfig.getInt(
+            mMinNumSystemGeneratedReplies = mDeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES,
                     mDefaultMinNumSystemGeneratedReplies);
-            mMaxNumActions = DeviceConfig.getInt(
+            mMaxNumActions = mDeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS,
                     mDefaultMaxNumActions);
-            mOnClickInitDelay = DeviceConfig.getInt(
+            mOnClickInitDelay = mDeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY,
                     mDefaultOnClickInitDelay);
         }
     }
 
-    private static boolean readDeviceConfigBooleanOrDefaultIfEmpty(String propertyName,
+    private boolean readDeviceConfigBooleanOrDefaultIfEmpty(String propertyName,
             boolean defaultValue) {
-        String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName);
+        String value = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName);
         if (TextUtils.isEmpty(value)) {
             return defaultValue;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index cfa2947..5f82118 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -126,9 +126,10 @@
 
     /**
      * Allow the media player to be shown in the QS area, controlled by 2 flags.
+     * On by default, but can be disabled by setting to 0
      */
     public static boolean useQsMediaPlayer(Context context) {
-        int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
+        int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 1);
         return flag > 0;
     }
 }
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/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index a974c6d..1b34b3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -456,4 +456,52 @@
         assertThat(rectsToRegion(Collections.singletonList(rect)).getBounds(), is(rect));
     }
 
+    @Test
+    public void testRegistration_From_NoOverlay_To_HasOverlays() {
+        doReturn(false).when(mScreenDecorations).hasOverlays();
+        mScreenDecorations.start();
+        verify(mTunerService, times(0)).addTunable(any(), any());
+        verify(mTunerService, times(1)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(false));
+        reset(mTunerService);
+
+        doReturn(true).when(mScreenDecorations).hasOverlays();
+        mScreenDecorations.onConfigurationChanged(new Configuration());
+        verify(mTunerService, times(1)).addTunable(any(), any());
+        verify(mTunerService, times(0)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(true));
+    }
+
+    @Test
+    public void testRegistration_From_HasOverlays_To_HasOverlays() {
+        doReturn(true).when(mScreenDecorations).hasOverlays();
+
+        mScreenDecorations.start();
+        verify(mTunerService, times(1)).addTunable(any(), any());
+        verify(mTunerService, times(0)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(true));
+        reset(mTunerService);
+
+        mScreenDecorations.onConfigurationChanged(new Configuration());
+        verify(mTunerService, times(0)).addTunable(any(), any());
+        verify(mTunerService, times(0)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(true));
+    }
+
+    @Test
+    public void testRegistration_From_HasOverlays_To_NoOverlay() {
+        doReturn(true).when(mScreenDecorations).hasOverlays();
+
+        mScreenDecorations.start();
+        verify(mTunerService, times(1)).addTunable(any(), any());
+        verify(mTunerService, times(0)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(true));
+        reset(mTunerService);
+
+        doReturn(false).when(mScreenDecorations).hasOverlays();
+        mScreenDecorations.onConfigurationChanged(new Configuration());
+        verify(mTunerService, times(0)).addTunable(any(), any());
+        verify(mTunerService, times(1)).removeTunable(any());
+        assertThat(mScreenDecorations.mIsRegistered, is(false));
+    }
 }
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/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 9ef5520..8320b05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -44,6 +44,8 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -69,6 +71,7 @@
     private @Mock DumpManager mDumpManager;
     private @Mock PowerManager mPowerManager;
     private @Mock TrustManager mTrustManager;
+    private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
     private FalsingManagerFake mFalsingManager;
@@ -85,7 +88,7 @@
                 mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
                 mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager,
                 mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
-                mPowerManager, mTrustManager);
+                mPowerManager, mTrustManager, mDeviceConfig);
         mViewMediator.start();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 8e87e0a..cc5f149 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -41,11 +41,11 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.DynamicChildBindController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -106,17 +106,14 @@
                 mock(KeyguardBypassController.class),
                 mock(BubbleController.class),
                 mock(DynamicPrivacyController.class),
-                mock(ForegroundServiceSectionController.class));
+                mock(ForegroundServiceSectionController.class),
+                mock(DynamicChildBindController.class));
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
 
     private NotificationEntry createEntry() throws Exception {
         ExpandableNotificationRow row = mHelper.createRow();
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setSbn(row.getEntry().getSbn())
-                .build();
-        entry.setRow(row);
-        return entry;
+        return row.getEntry();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
new file mode 100644
index 0000000..bf2d598
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.statusbar.notification;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.RowContentBindParams;
+import com.android.systemui.statusbar.notification.row.RowContentBindStage;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class DynamicChildBindControllerTest extends SysuiTestCase {
+
+    private DynamicChildBindController mDynamicChildBindController;
+    private Map<NotificationEntry, List<NotificationEntry>> mGroupNotifs = new ArrayMap<>();
+    private static final int TEST_CHILD_BIND_CUTOFF = 5;
+
+    @Mock private RowContentBindStage mBindStage;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        allowTestableLooperAsMainThread();
+        when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
+        mDynamicChildBindController =
+                new DynamicChildBindController(mBindStage, TEST_CHILD_BIND_CUTOFF);
+    }
+
+    @Test
+    public void testContentViewsOfChildrenBeyondCutoffAreFreed() {
+        // GIVEN a group notification with one view beyond the cutoff with content bound
+        NotificationEntry summary = addGroup(TEST_CHILD_BIND_CUTOFF + 1);
+        NotificationEntry lastChild = mGroupNotifs.get(summary).get(TEST_CHILD_BIND_CUTOFF);
+
+        RowContentBindParams bindParams = mock(RowContentBindParams.class);
+        when(mBindStage.getStageParams(lastChild)).thenReturn(bindParams);
+
+        // WHEN the controller gets the list
+        mDynamicChildBindController.updateChildContentViews(mGroupNotifs);
+
+        // THEN we free content views
+        verify(bindParams).freeContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+        verify(bindParams).freeContentViews(FLAG_CONTENT_VIEW_EXPANDED);
+        verify(mBindStage).requestRebind(eq(lastChild), any());
+    }
+
+    @Test
+    public void testContentViewsBeforeCutoffAreBound() {
+        // GIVEN a group notification with one view before the cutoff with content unbound
+        NotificationEntry summary = addGroup(TEST_CHILD_BIND_CUTOFF);
+        NotificationEntry lastChild = mGroupNotifs.get(summary).get(TEST_CHILD_BIND_CUTOFF - 1);
+
+        lastChild.getRow().getPrivateLayout().setContractedChild(null);
+        lastChild.getRow().getPrivateLayout().setExpandedChild(null);
+
+        RowContentBindParams bindParams = mock(RowContentBindParams.class);
+        when(mBindStage.getStageParams(lastChild)).thenReturn(bindParams);
+
+        // WHEN the controller gets the list
+        mDynamicChildBindController.updateChildContentViews(mGroupNotifs);
+
+        // THEN we bind content views
+        verify(bindParams).requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
+        verify(bindParams).requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
+        verify(mBindStage).requestRebind(eq(lastChild), any());
+    }
+
+    private NotificationEntry addGroup(int size) {
+        NotificationEntry summary = new NotificationEntryBuilder().build();
+        summary.setRow(createRow());
+        ArrayList<NotificationEntry> children = new ArrayList<>();
+        for (int i = 0; i < size; i++) {
+            NotificationEntry child = new NotificationEntryBuilder().build();
+            child.setRow(createRow());
+            children.add(child);
+        }
+        mGroupNotifs.put(summary, children);
+        return summary;
+    }
+
+    private ExpandableNotificationRow createRow() {
+        ExpandableNotificationRow row = (ExpandableNotificationRow)
+                LayoutInflater.from(mContext).inflate(R.layout.status_bar_notification_row, null);
+        row.getPrivateLayout().setContractedChild(new View(mContext));
+        row.getPrivateLayout().setExpandedChild(new View(mContext));
+        return row;
+    }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
index 69e4f22..18ea774 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java
@@ -25,6 +25,7 @@
 import android.media.MediaMetadata;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
@@ -66,6 +67,9 @@
         allowTestableLooperAsMainThread();
 
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+
+        // These tests are for regular media style notifications, not controls in quick settings
+        Settings.System.putInt(mContext.getContentResolver(), "qs_media_player", 0);
     }
 
     private void makeTestNotification(long duration, boolean allowSeeking) throws Exception {
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/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index e6b0440..44184ee 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
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -28,6 +29,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -37,7 +39,6 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.NetworkRequest;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.UserManager;
 import android.security.IKeyChainService;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -46,34 +47,30 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class SecurityControllerTest extends SysuiTestCase implements SecurityControllerCallback {
+public class SecurityControllerTest extends SysuiTestCase {
     private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
     private final IKeyChainService.Stub mKeyChainService = mock(IKeyChainService.Stub.class);
     private final UserManager mUserManager = mock(UserManager.class);
+    private final BroadcastDispatcher mBroadcastDispatcher = mock(BroadcastDispatcher.class);
+    private final Handler mHandler = mock(Handler.class);
     private SecurityControllerImpl mSecurityController;
-    private CountDownLatch mStateChangedLatch;
     private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class);
-
-    // implementing SecurityControllerCallback
-    @Override
-    public void onStateChanged() {
-        mStateChangedLatch.countDown();
-    }
+    private FakeExecutor mBgExecutor;
+    private BroadcastReceiver mBroadcastReceiver;
 
     @Before
     public void setUp() throws Exception {
@@ -95,18 +92,23 @@
         when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService"))
                 .thenReturn(mKeyChainService);
 
-        // Wait for callbacks from the onUserSwitched() function in the
-        // constructor of mSecurityController
-        mStateChangedLatch = new CountDownLatch(1);
-        // TODO: Migrate this test to TestableLooper and use a handler attached
-        // to that.
-        mSecurityController = new SecurityControllerImpl(mContext,
-                new Handler(Looper.getMainLooper()), mock(BroadcastDispatcher.class), this);
-    }
+        ArgumentCaptor<BroadcastReceiver> brCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
 
-    @After
-    public void tearDown() {
-        mSecurityController.removeCallback(this);
+        mBgExecutor = new FakeExecutor(new FakeSystemClock());
+        mSecurityController = new SecurityControllerImpl(
+                mContext,
+                mHandler,
+                mBroadcastDispatcher,
+                mBgExecutor);
+
+        verify(mBroadcastDispatcher).registerReceiverWithHandler(
+                brCaptor.capture(),
+                anyObject(),
+                anyObject(),
+                anyObject());
+
+        mBroadcastReceiver = brCaptor.getValue();
     }
 
     @Test
@@ -126,8 +128,6 @@
 
     @Test
     public void testWorkAccount() throws Exception {
-        // Wait for the callbacks from setUp()
-        assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS));
         assertFalse(mSecurityController.hasCACertInCurrentUser());
 
         final int PRIMARY_USER_ID = 0;
@@ -140,53 +140,41 @@
         assertTrue(mSecurityController.hasWorkProfile());
         assertFalse(mSecurityController.hasCACertInWorkProfile());
 
-        mStateChangedLatch = new CountDownLatch(1);
-
         when(mKeyChainService.getUserCaAliases())
                 .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
 
-        mSecurityController.new CACertLoader()
-                           .execute(MANAGED_USER_ID);
+        refreshCACerts(MANAGED_USER_ID);
+        mBgExecutor.runAllReady();
 
-        assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
         assertTrue(mSecurityController.hasCACertInWorkProfile());
     }
 
     @Test
     public void testCaCertLoader() throws Exception {
-        // Wait for the callbacks from setUp()
-        assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS));
         assertFalse(mSecurityController.hasCACertInCurrentUser());
 
         // With a CA cert
-        mStateChangedLatch = new CountDownLatch(1);
-
         when(mKeyChainService.getUserCaAliases())
                 .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
 
-        mSecurityController.new CACertLoader()
-                           .execute(0);
+        refreshCACerts(0);
+        mBgExecutor.runAllReady();
 
-        assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
         assertTrue(mSecurityController.hasCACertInCurrentUser());
 
         // Exception
-        mStateChangedLatch = new CountDownLatch(1);
-
         when(mKeyChainService.getUserCaAliases())
                 .thenThrow(new AssertionError("Test AssertionError"))
                 .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
 
-        mSecurityController.new CACertLoader()
-                           .execute(0);
+        refreshCACerts(0);
+        mBgExecutor.runAllReady();
 
-        assertFalse(mStateChangedLatch.await(1, TimeUnit.SECONDS));
         assertTrue(mSecurityController.hasCACertInCurrentUser());
 
-        mSecurityController.new CACertLoader()
-                           .execute(0);
+        refreshCACerts(0);
+        mBgExecutor.runAllReady();
 
-        assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS));
         assertFalse(mSecurityController.hasCACertInCurrentUser());
     }
 
@@ -197,4 +185,13 @@
                         && request.networkCapabilities.getCapabilities().length == 0
                 ), any(NetworkCallback.class));
     }
+
+    /**
+     * refresh CA certs by sending a user unlocked broadcast for the desired user
+     */
+    private void refreshCACerts(int userId) {
+        Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        mBroadcastReceiver.onReceive(mContext, intent);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index c761a44..e4e0dc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -22,7 +22,6 @@
 
 import android.app.RemoteInput;
 import android.os.Handler;
-import android.os.Looper;
 import android.provider.DeviceConfig;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -32,8 +31,8 @@
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.DeviceConfigProxyFake;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,14 +41,13 @@
 @TestableLooper.RunWithLooper
 @SmallTest
 public class SmartReplyConstantsTest extends SysuiTestCase {
-
-    private static final int CONTENT_OBSERVER_TIMEOUT_SECONDS = 10;
-
     private SmartReplyConstants mConstants;
+    private DeviceConfigProxyFake mDeviceConfig;
+    private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() {
-        resetAllDeviceConfigFlags();
+        mDeviceConfig = new DeviceConfigProxyFake();
         TestableResources resources = mContext.getOrCreateTestableResources();
         resources.addOverride(R.bool.config_smart_replies_in_notifications_enabled, true);
         resources.addOverride(
@@ -62,12 +60,12 @@
                 2);
         resources.addOverride(
                 R.integer.config_smart_replies_in_notifications_max_num_actions, -1);
-        mConstants = new SmartReplyConstants(Handler.createAsync(Looper.myLooper()), mContext);
-    }
-
-    @After
-    public void tearDown() {
-        resetAllDeviceConfigFlags();
+        mTestableLooper = TestableLooper.get(this);
+        mConstants = new SmartReplyConstants(
+                new Handler(mTestableLooper.getLooper()),
+                mContext,
+                mDeviceConfig
+        );
     }
 
     @Test
@@ -78,25 +76,21 @@
     @Test
     public void testIsEnabledWithInvalidConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_ENABLED, "invalid config");
-        triggerConstantsOnChange();
         assertTrue(mConstants.isEnabled());
     }
 
     @Test
     public void testIsEnabledWithValidConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_ENABLED, "false");
-        triggerConstantsOnChange();
         assertFalse(mConstants.isEnabled());
     }
 
     @Test
     public void testRequiresTargetingPConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, "false");
-        triggerConstantsOnChange();
         assertEquals(false, mConstants.requiresTargetingP());
 
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, null);
-        triggerConstantsOnChange();
         assertEquals(true, mConstants.requiresTargetingP());
     }
 
@@ -110,20 +104,17 @@
     public void testGetMaxSqueezeRemeasureAttemptsWithInvalidConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS,
                 "invalid config");
-        triggerConstantsOnChange();
         assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts());
     }
 
     @Test
     public void testGetMaxSqueezeRemeasureAttemptsWithValidConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, "5");
-        triggerConstantsOnChange();
         assertEquals(5, mConstants.getMaxSqueezeRemeasureAttempts());
     }
 
     @Test
     public void testGetEffectiveEditChoicesBeforeSendingWithNoConfig() {
-        triggerConstantsOnChange();
         assertFalse(
                 mConstants.getEffectiveEditChoicesBeforeSending(
                         RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
@@ -138,7 +129,6 @@
     @Test
     public void testGetEffectiveEditChoicesBeforeSendingWithEnabledConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, "true");
-        triggerConstantsOnChange();
         assertTrue(
                 mConstants.getEffectiveEditChoicesBeforeSending(
                         RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
@@ -153,7 +143,6 @@
     @Test
     public void testGetEffectiveEditChoicesBeforeSendingWithDisabledConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, "false");
-        triggerConstantsOnChange();
         assertFalse(
                 mConstants.getEffectiveEditChoicesBeforeSending(
                         RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
@@ -174,14 +163,12 @@
     @Test
     public void testShowInHeadsUpEnabled() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, "true");
-        triggerConstantsOnChange();
         assertTrue(mConstants.getShowInHeadsUp());
     }
 
     @Test
     public void testShowInHeadsUpDisabled() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, "false");
-        triggerConstantsOnChange();
         assertFalse(mConstants.getShowInHeadsUp());
     }
 
@@ -194,7 +181,6 @@
     @Test
     public void testGetMinNumSystemGeneratedRepliesWithValidConfig() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES, "5");
-        triggerConstantsOnChange();
         assertEquals(5, mConstants.getMinNumSystemGeneratedReplies());
     }
 
@@ -207,7 +193,6 @@
     @Test
     public void testMaxNumActionsSet() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS, "10");
-        triggerConstantsOnChange();
         assertEquals(10, mConstants.getMaxNumActions());
     }
 
@@ -219,38 +204,12 @@
     @Test
     public void testOnClickInitDelaySet() {
         overrideSetting(SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY, "50");
-        triggerConstantsOnChange();
         assertEquals(50, mConstants.getOnClickInitDelay());
     }
 
     private void overrideSetting(String propertyName, String value) {
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+        mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 propertyName, value, false /* makeDefault */);
-    }
-
-    private void triggerConstantsOnChange() {
-        mConstants.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
-    }
-
-    private void resetAllDeviceConfigFlags() {
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_ENABLED, null, false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, null, false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, null,
-                false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, null,
-                false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, null, false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES, null,
-                false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS, null, false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY, null, false /* makeDefault */);
+        mTestableLooper.processAllMessages();
     }
 }
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/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 1eb7692..228c628 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -47,6 +47,7 @@
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
 import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
 
 import com.android.internal.infra.AbstractRemoteService;
 import com.android.internal.infra.AndroidFuture;
@@ -243,20 +244,27 @@
         }
         mCallbacks.setLastResponse(sessionId);
 
+        final InlineSuggestionsResponse inlineSuggestionsResponse =
+                InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
+                        request, inlineSuggestionsData, focusedId, mContext,
+                        dataset -> {
+                            mCallbacks.logAugmentedAutofillSelected(sessionId,
+                                    dataset.getId());
+                            try {
+                                client.autofill(sessionId, dataset.getFieldIds(),
+                                        dataset.getFieldValues());
+                            } catch (RemoteException e) {
+                                Slog.w(TAG, "Encounter exception autofilling the values");
+                            }
+                        }, onErrorCallback, remoteRenderService);
+
+        if (inlineSuggestionsResponse == null) {
+            Slog.w(TAG, "InlineSuggestionFactory created null response");
+            return;
+        }
+
         try {
-            inlineSuggestionsCallback.onInlineSuggestionsResponse(
-                    InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
-                            request, inlineSuggestionsData, focusedId, mContext,
-                            dataset -> {
-                                mCallbacks.logAugmentedAutofillSelected(sessionId,
-                                        dataset.getId());
-                                try {
-                                    client.autofill(sessionId, dataset.getFieldIds(),
-                                            dataset.getFieldValues());
-                                } catch (RemoteException e) {
-                                    Slog.w(TAG, "Encounter exception autofilling the values");
-                                }
-                            }, onErrorCallback, remoteRenderService));
+            inlineSuggestionsCallback.onInlineSuggestionsResponse(inlineSuggestionsResponse);
         } catch (RemoteException e) {
             Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
         }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 317ce4c..960997d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2686,6 +2686,12 @@
                                 requestHideFillUi(mCurrentViewId);
                             }
                         }, mService.getRemoteInlineSuggestionRenderServiceLocked());
+
+        if (inlineSuggestionsResponse == null) {
+            Slog.w(TAG, "InlineSuggestionFactory created null response");
+            return false;
+        }
+
         try {
             imeResponse.getCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse);
         } catch (RemoteException e) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index fef49d4..0d1b6dd 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -150,13 +150,13 @@
             final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
             if (fieldIndex < 0) {
                 Slog.w(TAG, "AutofillId=" + autofillId + " not found in dataset");
-                return null;
+                continue;
             }
             final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(
                     fieldIndex);
             if (inlinePresentation == null) {
                 Slog.w(TAG, "InlinePresentation not found in dataset");
-                return null;
+                continue;
             }
             if (!includeDataset(dataset, fieldIndex, filterText)) {
                 continue;
@@ -219,12 +219,12 @@
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
             @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
             int displayId) {
-        // TODO(b/146453195): fill in the autofill hint properly.
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                 inlinePresentation.getInlinePresentationSpec(),
                 isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
-                        : InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
-                InlineSuggestionInfo.TYPE_ACTION);
+                        : InlineSuggestionInfo.SOURCE_AUTOFILL,
+                inlinePresentation.getAutofillHints(),
+                InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned());
         final Runnable onClickAction = () -> {
             Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show();
         };
@@ -240,12 +240,12 @@
             @NonNull RemoteInlineSuggestionRenderService remoteRenderService,
             @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
             int displayId) {
-        // TODO(b/146453195): fill in the autofill hint properly.
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                 inlinePresentation.getInlinePresentationSpec(),
                 isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
-                        : InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
-                InlineSuggestionInfo.TYPE_SUGGESTION);
+                        : InlineSuggestionInfo.SOURCE_AUTOFILL,
+                inlinePresentation.getAutofillHints(),
+                InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned());
 
         final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlinePresentation,
@@ -262,7 +262,8 @@
             @Nullable IBinder hostInputToken, int displayId) {
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                 inlinePresentation.getInlinePresentationSpec(),
-                InlineSuggestionInfo.SOURCE_AUTOFILL, null, InlineSuggestionInfo.TYPE_SUGGESTION);
+                InlineSuggestionInfo.SOURCE_AUTOFILL, inlinePresentation.getAutofillHints(),
+                InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned());
 
         return new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlinePresentation,
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 3180ceb..84ce34b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -127,6 +127,8 @@
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
         "netd_event_listener_interface-java",
+        "ike-stubs",
+        "overlayable_policy_aidl-java",
     ],
 
     plugins: [
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 0f1a652..dd9cc64 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -183,7 +183,8 @@
     static native boolean vibratorSupportsAmplitudeControl();
     static native void vibratorSetAmplitude(int amplitude);
     static native int[] vibratorGetSupportedEffects();
-    static native long vibratorPerformEffect(long effect, long strength, Vibration vibration);
+    static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
+            boolean withCallback);
     static native void vibratorPerformComposedEffect(
             VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
     static native boolean vibratorSupportsExternalControl();
@@ -1334,7 +1335,8 @@
             // Input devices don't support prebaked effect, so skip trying it with them.
             if (!usingInputDeviceVibrators) {
                 long duration = vibratorPerformEffect(prebaked.getId(),
-                        prebaked.getEffectStrength(), vib);
+                        prebaked.getEffectStrength(), vib,
+                        hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
                 long timeout = duration;
                 if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) {
                     timeout *= ASYNC_TIMEOUT_MULTIPLIER;
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 211da0a..b7b52b1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3501,8 +3501,11 @@
                 }
             }
 
-            // If unbound while waiting to start, remove the pending service
-            mPendingServices.remove(s);
+            // If unbound while waiting to start and there is no connection left in this service,
+            // remove the pending service
+            if (s.getConnections().isEmpty()) {
+                mPendingServices.remove(s);
+            }
 
             if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                 boolean hasAutoCreate = s.hasAutoCreateConnections();
@@ -4869,6 +4872,19 @@
             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;
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/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 60aba27..cba6b92 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -708,7 +708,7 @@
 
     void dumpHistoryProcessExitInfo(PrintWriter pw, String packageName) {
         pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity exit-info)");
-        SimpleDateFormat sdf = new SimpleDateFormat();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
         synchronized (mLock) {
             pw.println("Last Timestamp of Persistence Into Persistent Storage: "
                     + sdf.format(new Date(mLastAppExitInfoPersistTimestamp)));
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 119394f..dbad562 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import android.app.ActivityManager;
-import android.app.job.JobProtoEnums;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -468,26 +467,18 @@
     }
 
     /** A scheduled job was started. */
-    public void noteJobStart(String name, int uid, int standbyBucket, int jobid) {
+    public void noteJobStart(String name, int uid) {
         enforceCallingPermission();
         synchronized (mStats) {
             mStats.noteJobStartLocked(name, uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                    uid, null, name,
-                    FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED,
-                    JobProtoEnums.STOP_REASON_UNKNOWN, standbyBucket, jobid);
         }
     }
 
     /** A scheduled job was finished. */
-    public void noteJobFinish(String name, int uid, int stopReason, int standbyBucket, int jobid) {
+    public void noteJobFinish(String name, int uid, int stopReason) {
         enforceCallingPermission();
         synchronized (mStats) {
             mStats.noteJobFinishLocked(name, uid, stopReason);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                    uid, null, name,
-                    FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED, stopReason,
-                    standbyBucket, jobid);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index eec68dc..be48374 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -911,10 +911,12 @@
                 pid = proc.pid;
                 name = proc.processName;
 
-                if (proc.curAdj <= ProcessList.CACHED_APP_MIN_ADJ) {
+                if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ
+                        || proc.shouldNotFreeze) {
                     if (DEBUG_FREEZER) {
                         Slog.d(TAG_AM, "Skipping freeze for process " + pid
-                                + " " + name + " (not cached)");
+                                + " " + name + " curAdj = " + proc.curAdj
+                                + ", shouldNotFreeze = " + proc.shouldNotFreeze);
                     }
                     return;
                 }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c239feb1..3fd1b78 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1109,6 +1109,7 @@
         app.adjTarget = null;
         app.empty = false;
         app.setCached(false);
+        app.shouldNotFreeze = false;
 
         final int appUid = app.info.uid;
         final int logUid = mService.mCurOomAdjUid;
@@ -1542,23 +1543,24 @@
                     }
 
                     boolean trackedProcState = false;
-                    if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {
-                        ProcessRecord client = cr.binding.client;
-                        if (computeClients) {
-                            computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now,
-                                    cycleReEval, true);
-                        } else {
-                            client.setCurRawAdj(client.setAdj);
-                            client.setCurRawProcState(client.setProcState);
-                        }
 
+                    ProcessRecord client = cr.binding.client;
+                    if (computeClients) {
+                        computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now,
+                                cycleReEval, true);
+                    } else {
+                        client.setCurRawAdj(client.setAdj);
+                        client.setCurRawProcState(client.setProcState);
+                    }
+
+                    int clientAdj = client.getCurRawAdj();
+                    int clientProcState = client.getCurRawProcState();
+
+                    if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
                         if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
                             continue;
                         }
 
-                        int clientAdj = client.getCurRawAdj();
-                        int clientProcState = client.getCurRawProcState();
-
                         if (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE) {
                             procStateFromFGSClient = true;
                         }
@@ -1762,6 +1764,19 @@
                                         + ProcessList.makeProcStateString(procState));
                             }
                         }
+                    } else { // BIND_WAIVE_PRIORITY == true
+                        // BIND_WAIVE_PRIORITY bindings are special when it comes to the
+                        // freezer. Processes bound via WPRI are expected to be running,
+                        // but they are not promoted in the LRU list to keep them out of
+                        // cached. As a result, they can freeze based on oom_adj alone.
+                        // Normally, bindToDeath would fire when a cached app would die
+                        // in the background, but nothing will fire when a running process
+                        // pings a frozen process. Accordingly, any cached app that is
+                        // bound by an unfrozen app via a WPRI binding has to remain
+                        // unfrozen.
+                        if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) {
+                            app.shouldNotFreeze = true;
+                        }
                     }
                     if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                         app.treatLikeActivity = true;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c2f03ec..f2ca1da 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -167,6 +167,7 @@
     int lastCompactAction;      // The most recent compaction action performed for this app.
     boolean frozen;             // True when the process is frozen.
     long freezeUnfreezeTime;    // Last time the app was (un)frozen, 0 for never
+    boolean shouldNotFreeze;    // True if a process has a WPRI binding from an unfrozen process
     private int mCurSchedGroup; // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
     int trimMemoryLevel;        // Last selected memory trimming level
diff --git a/services/core/java/com/android/server/backup/PeopleBackupHelper.java b/services/core/java/com/android/server/backup/PeopleBackupHelper.java
index e58a051..555e006 100644
--- a/services/core/java/com/android/server/backup/PeopleBackupHelper.java
+++ b/services/core/java/com/android/server/backup/PeopleBackupHelper.java
@@ -50,7 +50,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Handling backup of " + key);
         }
-        return ps.backupConversationInfos(mUserId);
+        return ps.getBackupPayload(mUserId);
     }
 
     @Override
@@ -63,6 +63,6 @@
         if (DEBUG) {
             Slog.d(TAG, "Handling restore of " + key);
         }
-        ps.restoreConversationInfos(mUserId, key, payload);
+        ps.restore(mUserId, payload);
     }
 }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 7f7c9c4..441d9d9 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -16,6 +16,7 @@
 
 package com.android.server.compat;
 
+import android.app.compat.ChangeIdStateCache;
 import android.compat.Compatibility.ChangeConfig;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -80,6 +81,7 @@
     void addChange(CompatChange change) {
         synchronized (mChanges) {
             mChanges.put(change.getId(), change);
+            invalidateCache();
         }
     }
 
@@ -172,6 +174,7 @@
                 addChange(c);
             }
             c.addPackageOverride(packageName, enabled);
+            invalidateCache();
         }
         return alreadyKnown;
     }
@@ -228,6 +231,7 @@
                 // Should never occur, since validator is in the same process.
                 throw new RuntimeException("Unable to call override validator!", e);
             }
+            invalidateCache();
         }
         return overrideExists;
     }
@@ -250,6 +254,7 @@
                 addOverride(changeId, packageName, false);
 
             }
+            invalidateCache();
         }
     }
 
@@ -279,6 +284,7 @@
                     throw new RuntimeException("Unable to call override validator!", e);
                 }
             }
+            invalidateCache();
         }
     }
 
@@ -377,6 +383,7 @@
             config.initConfigFromLib(Environment.buildPath(
                     apex.apexDirectory, "etc", "compatconfig"));
         }
+        config.invalidateCache();
         return config;
     }
 
@@ -406,4 +413,8 @@
     IOverrideValidator getOverrideValidator() {
         return mOverrideValidator;
     }
+
+    private void invalidateCache() {
+        ChangeIdStateCache.invalidate();
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index e3c545c..dcd0a78 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -846,6 +846,14 @@
     private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
 
     /**
+     * Map of generated token to windowToken that is requesting
+     * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
+     * This map tracks origin of hideSoftInput requests.
+     */
+    @GuardedBy("mMethodMap")
+    private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
+
+    /**
      * A ring buffer to store the history of {@link StartInputInfo}.
      */
     private static final class StartInputHistory {
@@ -1064,7 +1072,7 @@
                                     == AccessibilityService.SHOW_MODE_HIDDEN;
                     if (mAccessibilityRequestingNoSoftKeyboard) {
                         final boolean showRequested = mShowRequested;
-                        hideCurrentInputLocked(0, null,
+                        hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                                 SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
                         mShowRequested = showRequested;
                     } else if (mShowRequested) {
@@ -1695,7 +1703,9 @@
 
         // TODO: Is it really possible that switchUserLocked() happens before system ready?
         if (mSystemReady) {
-            hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
+            hideCurrentInputLocked(
+                    mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
+
             resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
             buildInputMethodListLocked(initialUserSwitch);
             if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
@@ -3040,7 +3050,7 @@
     }
 
     @Override
-    public boolean hideSoftInput(IInputMethodClient client, int flags,
+    public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
             ResultReceiver resultReceiver) {
         int uid = Binder.getCallingUid();
         synchronized (mMethodMap) {
@@ -3068,7 +3078,7 @@
                 }
 
                 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
-                return hideCurrentInputLocked(flags, resultReceiver,
+                return hideCurrentInputLocked(windowToken, flags, resultReceiver,
                         SoftInputShowHideReason.HIDE_SOFT_INPUT);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -3076,7 +3086,7 @@
         }
     }
 
-    boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver,
+    boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mShowExplicitlyRequested || mShowForced)) {
@@ -3100,12 +3110,14 @@
                 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
         boolean res;
         if (shouldHideSoftInput) {
+            final Binder hideInputToken = new Binder();
+            mHideRequestWindowMap.put(hideInputToken, windowToken);
             // The IME will report its visible state again after the following message finally
             // delivered to the IME process as an IPC.  Hence the inconsistency between
             // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
             // the final state.
-            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_HIDE_SOFT_INPUT,
-                    reason, mCurMethod, resultReceiver));
+            executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
+                    reason, mCurMethod, resultReceiver, hideInputToken));
             res = true;
         } else {
             res = false;
@@ -3242,7 +3254,8 @@
             Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
                     + " a background user, use EditorInfo.targetInputMethodUser with"
                     + " INTERACT_ACROSS_USERS_FULL permission.");
-            hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_INVALID_USER);
+            hideCurrentInputLocked(
+                    mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_INVALID_USER);
             return InputBindResult.INVALID_USER;
         }
 
@@ -3305,7 +3318,8 @@
                         // be behind any soft input window, so hide the
                         // soft input window if it is shown.
                         if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
-                        hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null,
+                        hideCurrentInputLocked(
+                                mCurFocusedWindow, InputMethodManager.HIDE_NOT_ALWAYS, null,
                                 SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
 
                         // If focused display changed, we should unbind current method
@@ -3342,13 +3356,13 @@
             case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
                 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                     if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
-                    hideCurrentInputLocked(0, null,
+                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                             SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
                 }
                 break;
             case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
                 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
-                hideCurrentInputLocked(0, null,
+                hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                         SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
                 break;
             case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
@@ -3832,7 +3846,7 @@
                     // Send it to window manager to hide IME from IME target window.
                     // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
                     // actual IME target.
-                    mWindowManagerInternal.hideIme(mCurClient.selfReportedDisplayId);
+                    mWindowManagerInternal.hideIme(mHideRequestWindowMap.get(windowToken));
                 }
             } else {
                 // Send to window manager to show IME after IME layout finishes.
@@ -3872,7 +3886,10 @@
             }
             long ident = Binder.clearCallingIdentity();
             try {
-                hideCurrentInputLocked(flags, null, SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
+                hideCurrentInputLocked(
+                        mLastImeTargetWindow, flags, null,
+                        SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
+
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -3969,11 +3986,11 @@
                 args.recycle();
                 return true;
             case MSG_SHOW_SOFT_INPUT:
-                args = (SomeArgs)msg.obj;
+                args = (SomeArgs) msg.obj;
                 try {
                     final @SoftInputShowHideReason int reason = msg.arg2;
                     if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
-                            + msg.arg1 + ", " + args.arg2 + ") for reason: "
+                            + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: "
                             + InputMethodDebug.softInputDisplayReasonToString(reason));
                     ((IInputMethod) args.arg1).showSoftInput(
                             (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
@@ -3986,13 +4003,14 @@
                 args.recycle();
                 return true;
             case MSG_HIDE_SOFT_INPUT:
-                args = (SomeArgs)msg.obj;
+                args = (SomeArgs) msg.obj;
                 try {
                     final @SoftInputShowHideReason int reason = msg.arg1;
                     if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
-                            + args.arg2 + ") for reason: "
+                            + args.arg3 + ", " + args.arg2 + ") for reason: "
                             + InputMethodDebug.softInputDisplayReasonToString(reason));
-                    ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
+                    ((IInputMethod)args.arg1).hideSoftInput(
+                            (IBinder) args.arg3, 0, (ResultReceiver)args.arg2);
                     mSoftInputShowHideHistory.addEntry(
                             new SoftInputShowHideHistory.Entry(mCurClient,
                                     InputMethodDebug.objToString(mCurFocusedWindow),
@@ -4004,7 +4022,8 @@
             case MSG_HIDE_CURRENT_INPUT_METHOD:
                 synchronized (mMethodMap) {
                     final @SoftInputShowHideReason int reason = (int) msg.obj;
-                    hideCurrentInputLocked(0, null, reason);
+                    hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason);
+
                 }
                 return true;
             case MSG_INITIALIZE_IME:
@@ -5409,7 +5428,7 @@
                 final String nextIme;
                 final List<InputMethodInfo> nextEnabledImes;
                 if (userId == mSettings.getCurrentUserId()) {
-                    hideCurrentInputLocked(0, null,
+                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                             SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
                     unbindCurrentMethodLocked();
                     // Reset the current IME
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 1aff23b0..e60b910 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1500,7 +1500,8 @@
         @BinderThread
         @Override
         public boolean hideSoftInput(
-                IInputMethodClient client, int flags, ResultReceiver resultReceiver) {
+                IInputMethodClient client, IBinder windowToken, int flags,
+                ResultReceiver resultReceiver) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int userId = UserHandle.getUserId(callingUid);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index fd8e159..b4ec359 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -79,8 +79,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /** Implementation of {@link AppIntegrityManagerService}. */
 public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
@@ -101,12 +103,14 @@
     private static final String TAG = "AppIntegrityManagerServiceImpl";
 
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
-    private static final String PACKAGE_INSTALLER = "com.google.android.packageinstaller";
     private static final String BASE_APK_FILE = "base.apk";
     private static final String ALLOWED_INSTALLERS_METADATA_NAME = "allowed-installers";
     private static final String ALLOWED_INSTALLER_DELIMITER = ",";
     private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|";
 
+    private static final Set<String> PACKAGE_INSTALLER = new HashSet<>(
+            Arrays.asList("com.google.android.packageinstaller", "com.android.packageinstaller"));
+
     // Access to files inside mRulesDir is protected by mRulesLock;
     private final Context mContext;
     private final Handler mHandler;
@@ -114,8 +118,6 @@
     private final RuleEvaluationEngine mEvaluationEngine;
     private final IntegrityFileManager mIntegrityFileManager;
 
-    private final boolean mCheckIntegrityForRuleProviders;
-
     /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
     public static AppIntegrityManagerServiceImpl create(Context context) {
         HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler");
@@ -126,13 +128,7 @@
                 LocalServices.getService(PackageManagerInternal.class),
                 RuleEvaluationEngine.getRuleEvaluationEngine(),
                 IntegrityFileManager.getInstance(),
-                handlerThread.getThreadHandler(),
-                Settings.Global.getInt(
-                        context.getContentResolver(),
-                        Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
-                        0)
-                        == 1
-        );
+                handlerThread.getThreadHandler());
     }
 
     @VisibleForTesting
@@ -141,14 +137,12 @@
             PackageManagerInternal packageManagerInternal,
             RuleEvaluationEngine evaluationEngine,
             IntegrityFileManager integrityFileManager,
-            Handler handler,
-            boolean checkIntegrityForRuleProviders) {
+            Handler handler) {
         mContext = context;
         mPackageManagerInternal = packageManagerInternal;
         mEvaluationEngine = evaluationEngine;
         mIntegrityFileManager = integrityFileManager;
         mHandler = handler;
-        mCheckIntegrityForRuleProviders = checkIntegrityForRuleProviders;
 
         IntentFilter integrityVerificationFilter = new IntentFilter();
         integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
@@ -259,7 +253,7 @@
             String installerPackageName = getInstallerPackageName(intent);
 
             // Skip integrity verification if the verifier is doing the install.
-            if (!mCheckIntegrityForRuleProviders
+            if (!integrityCheckIncludesRuleProvider()
                     && isRuleProvider(installerPackageName)) {
                 Slog.i(TAG, "Verifier doing the install. Skipping integrity check.");
                 mPackageManagerInternal.setIntegrityVerificationResult(
@@ -271,8 +265,6 @@
             List<String> installerCertificates =
                     getInstallerCertificateFingerprint(installerPackageName);
 
-            Slog.w(TAG, appCertificates.toString());
-
             AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder();
 
             builder.setPackageName(getPackageNameNormalized(packageName));
@@ -376,7 +368,7 @@
         // A common way for apps to install packages is to send an intent to PackageInstaller. In
         // that case, the installer will always show up as PackageInstaller which is not what we
         // want.
-        if (installer.equals(PACKAGE_INSTALLER)) {
+        if (PACKAGE_INSTALLER.contains(installer)) {
             int originatingUid = intent.getIntExtra(EXTRA_ORIGINATING_UID, -1);
             if (originatingUid < 0) {
                 Slog.e(TAG, "Installer is package installer but originating UID not found.");
@@ -631,4 +623,12 @@
         return getAllowedRuleProviders().stream()
                 .anyMatch(ruleProvider -> ruleProvider.equals(installerPackageName));
     }
+
+    private boolean integrityCheckIncludesRuleProvider() {
+        return Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
+                0)
+                == 1;
+    }
 }
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index b3546dc..a3523f2 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -80,7 +80,7 @@
 
     // Represents an HAL interface version. Instances of this class are created in the JNI layer
     // and returned through native methods.
-    private static class HalInterfaceVersion {
+    static class HalInterfaceVersion {
         final int mMajor;
         final int mMinor;
 
@@ -206,6 +206,10 @@
         native_set_satellite_blacklist(constellations, svids);
     }
 
+    HalInterfaceVersion getHalInterfaceVersion() {
+        return native_get_gnss_configuration_version();
+    }
+
     interface SetCarrierProperty {
         boolean set(int value);
     }
@@ -232,8 +236,7 @@
 
         logConfigurations();
 
-        final HalInterfaceVersion gnssConfigurationIfaceVersion =
-                native_get_gnss_configuration_version();
+        final HalInterfaceVersion gnssConfigurationIfaceVersion = getHalInterfaceVersion();
         if (gnssConfigurationIfaceVersion != null) {
             // Set to a range checked value.
             if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5c2bf26..58e332a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -807,10 +807,15 @@
 
         locationRequest.setProvider(provider);
 
-        // Ignore location settings if in emergency mode.
-        if (isUserEmergency && mNIHandler.getInEmergency()) {
-            locationRequest.setLocationSettingsIgnored(true);
-            durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER;
+        // Ignore location settings if in emergency mode. This is only allowed for
+        // isUserEmergency request (introduced in HAL v2.0), or DBH request in HAL v1.1.
+        if (mNIHandler.getInEmergency()) {
+            GnssConfiguration.HalInterfaceVersion halVersion =
+                    mGnssConfiguration.getHalInterfaceVersion();
+            if (isUserEmergency || (halVersion.mMajor < 2 && !independentFromGnss)) {
+                locationRequest.setLocationSettingsIgnored(true);
+                durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER;
+            }
         }
 
         Log.i(TAG,
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index f3c9128..7c9be2d 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -21,17 +21,17 @@
 
 import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
+import android.content.om.OverlayableInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.Build.VERSION_CODES;
-import android.os.IIdmap2;
+import android.os.OverlayablePolicy;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
-
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Handle the creation and deletion of idmap files.
@@ -55,11 +55,11 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
-    private final PackageManagerHelper mPackageManager;
+    private final OverlayableInfoCallback mOverlayableCallback;
     private final IdmapDaemon mIdmapDaemon;
 
-    IdmapManager(final PackageManagerHelper packageManager) {
-        mPackageManager = packageManager;
+    IdmapManager(final OverlayableInfoCallback verifyCallback) {
+        mOverlayableCallback = verifyCallback;
         mIdmapDaemon = IdmapDaemon.getInstance();
     }
 
@@ -148,40 +148,67 @@
     private int calculateFulfilledPolicies(@NonNull final PackageInfo targetPackage,
             @NonNull final PackageInfo overlayPackage, int userId)  {
         final ApplicationInfo ai = overlayPackage.applicationInfo;
-        int fulfilledPolicies = IIdmap2.POLICY_PUBLIC;
+        int fulfilledPolicies = OverlayablePolicy.PUBLIC;
 
         // Overlay matches target signature
-        if (mPackageManager.signaturesMatching(targetPackage.packageName,
+        if (mOverlayableCallback.signaturesMatching(targetPackage.packageName,
                 overlayPackage.packageName, userId)) {
-            fulfilledPolicies |= IIdmap2.POLICY_SIGNATURE;
+            fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
+        }
+
+        // Overlay matches actor signature
+        if (matchesActorSignature(targetPackage, overlayPackage, userId)) {
+            fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
         }
 
         // Vendor partition (/vendor)
         if (ai.isVendor()) {
-            return fulfilledPolicies | IIdmap2.POLICY_VENDOR_PARTITION;
+            return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
         }
 
         // Product partition (/product)
         if (ai.isProduct()) {
-            return fulfilledPolicies | IIdmap2.POLICY_PRODUCT_PARTITION;
+            return fulfilledPolicies | OverlayablePolicy.PRODUCT_PARTITION;
         }
 
         // Odm partition (/odm)
         if (ai.isOdm()) {
-            return fulfilledPolicies | IIdmap2.POLICY_ODM_PARTITION;
+            return fulfilledPolicies | OverlayablePolicy.ODM_PARTITION;
         }
 
         // Oem partition (/oem)
         if (ai.isOem()) {
-            return fulfilledPolicies | IIdmap2.POLICY_OEM_PARTITION;
+            return fulfilledPolicies | OverlayablePolicy.OEM_PARTITION;
         }
 
         // System_ext partition (/system_ext) is considered as system
         // Check this last since every partition except for data is scanned as system in the PMS.
         if (ai.isSystemApp() || ai.isSystemExt()) {
-            return fulfilledPolicies | IIdmap2.POLICY_SYSTEM_PARTITION;
+            return fulfilledPolicies | OverlayablePolicy.SYSTEM_PARTITION;
         }
 
         return fulfilledPolicies;
     }
+
+    private boolean matchesActorSignature(@NonNull PackageInfo targetPackage,
+            @NonNull PackageInfo overlayPackage, int userId) {
+        String targetOverlayableName = overlayPackage.targetOverlayableName;
+        if (targetOverlayableName != null) {
+            try {
+                OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
+                        targetPackage.packageName, targetOverlayableName, userId);
+                if (overlayableInfo != null) {
+                    String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
+                            overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
+                    if (mOverlayableCallback.signaturesMatching(actorPackageName,
+                            overlayPackage.packageName, userId)) {
+                        return true;
+                    }
+                }
+            } catch (IOException ignored) {
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 4c85603..40efb7c 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -17,7 +17,6 @@
 package com.android.server.om;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.om.OverlayInfo;
 import android.content.om.OverlayableInfo;
 import android.content.pm.ApplicationInfo;
@@ -46,7 +45,7 @@
     // By default, the reason is not logged to prevent leaks of why it failed
     private static final boolean DEBUG_REASON = false;
 
-    private final VerifyCallback mVerifyCallback;
+    private final OverlayableInfoCallback mOverlayableCallback;
 
     /**
      * @return nullable actor result with {@link ActorState} failure status
@@ -80,8 +79,8 @@
         return Pair.create(packageName, ActorState.ALLOWED);
     }
 
-    public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) {
-        mVerifyCallback = verifyCallback;
+    public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) {
+        mOverlayableCallback = overlayableCallback;
     }
 
     void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
@@ -117,7 +116,7 @@
                 return ActorState.ALLOWED;
         }
 
-        String[] callingPackageNames = mVerifyCallback.getPackagesForUid(callingUid);
+        String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid);
         if (ArrayUtils.isEmpty(callingPackageNames)) {
             return ActorState.NO_PACKAGES_FOR_UID;
         }
@@ -132,12 +131,12 @@
 
         if (TextUtils.isEmpty(targetOverlayableName)) {
             try {
-                if (mVerifyCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
+                if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
                     return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
                 } else {
                     // If there's no overlayable defined, fallback to the legacy permission check
                     try {
-                        mVerifyCallback.enforcePermission(
+                        mOverlayableCallback.enforcePermission(
                                 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                         // If the previous method didn't throw, check passed
@@ -153,7 +152,7 @@
 
         OverlayableInfo targetOverlayable;
         try {
-            targetOverlayable = mVerifyCallback.getOverlayableForTarget(targetPackageName,
+            targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName,
                     targetOverlayableName, userId);
         } catch (IOException e) {
             return ActorState.UNABLE_TO_GET_TARGET;
@@ -167,7 +166,7 @@
         if (TextUtils.isEmpty(actor)) {
             // If there's no actor defined, fallback to the legacy permission check
             try {
-                mVerifyCallback.enforcePermission(
+                mOverlayableCallback.enforcePermission(
                         android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
 
                 // If the previous method didn't throw, check passed
@@ -177,7 +176,7 @@
             }
         }
 
-        Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
+        Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors();
         Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
         ActorState actorUriState = actorUriPair.second;
         if (actorUriState != ActorState.ALLOWED) {
@@ -185,7 +184,7 @@
         }
 
         String packageName = actorUriPair.first;
-        PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId);
+        PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId);
         if (packageInfo == null) {
             return ActorState.MISSING_APP_INFO;
         }
@@ -211,7 +210,7 @@
      * For easier logging/debugging, a set of all possible failure/success states when running
      * enforcement.
      */
-    enum ActorState {
+    public enum ActorState {
         ALLOWED,
         INVALID_ACTOR,
         MISSING_NAMESPACE,
@@ -228,53 +227,4 @@
         UNABLE_TO_GET_TARGET,
         MISSING_LEGACY_PERMISSION
     }
-
-    /**
-     * Delegate to the system for querying information about packages.
-     */
-    public interface VerifyCallback {
-
-        /**
-         * Read from the APK and AndroidManifest of a package to return the overlayable defined for
-         * a given name.
-         *
-         * @throws IOException if the target can't be read
-         */
-        @Nullable
-        OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
-                @Nullable String targetOverlayableName, int userId)
-                throws IOException;
-
-        /**
-         * @see android.content.pm.PackageManager#getPackagesForUid(int)
-         */
-        @Nullable
-        String[] getPackagesForUid(int uid);
-
-        /**
-         * @param userId user to filter package visibility by
-         * @see android.content.pm.PackageManager#getPackageInfo(String, int)
-         */
-        @Nullable
-        PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-
-        /**
-         * @return map of system pre-defined, uniquely named actors; keys are namespace,
-         * value maps actor name to package name
-         */
-        @NonNull
-        Map<String, Map<String, String>> getNamedActors();
-
-        /**
-         * @return true if the target package has declared an overlayable
-         */
-        boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
-                throws RemoteException, IOException;
-
-        /**
-         * @throws SecurityException containing message if the caller doesn't have the given
-         *                           permission
-         */
-        void enforcePermission(String permission, String message) throws SecurityException;
-    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f221285..c81f7cd 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -226,7 +226,7 @@
 
     private final AtomicFile mSettingsFile;
 
-    private final PackageManagerHelper mPackageManager;
+    private final PackageManagerHelperImpl mPackageManager;
 
     private final UserManagerService mUserManager;
 
@@ -244,7 +244,7 @@
             traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
             mSettingsFile = new AtomicFile(
                     new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
-            mPackageManager = new PackageManagerHelper(context);
+            mPackageManager = new PackageManagerHelperImpl(context);
             mUserManager = UserManagerService.getInstance();
             IdmapManager im = new IdmapManager(mPackageManager);
             mSettings = new OverlayManagerSettings();
@@ -1053,14 +1053,8 @@
         }
     }
 
-    /**
-     * Delegate for {@link android.content.pm.PackageManager} and {@link PackageManagerInternal}
-     * functionality, separated for easy testing.
-     *
-     * @hide
-     */
-    public static final class PackageManagerHelper implements
-            OverlayManagerServiceImpl.PackageManagerHelper, OverlayActorEnforcer.VerifyCallback {
+    private static final class PackageManagerHelperImpl implements PackageManagerHelper,
+            OverlayableInfoCallback {
 
         private final Context mContext;
         private final IPackageManager mPackageManager;
@@ -1073,7 +1067,7 @@
         // behind until all pending intents have been processed.
         private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
 
-        PackageManagerHelper(Context context) {
+        PackageManagerHelperImpl(Context context) {
             mContext = context;
             mPackageManager = getPackageManager();
             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
@@ -1132,7 +1126,7 @@
         @Nullable
         @Override
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
-                @Nullable String targetOverlayableName, int userId)
+                @NonNull String targetOverlayableName, int userId)
                 throws IOException {
             PackageInfo packageInfo = getPackageInfo(packageName, userId);
             if (packageInfo == null) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 2493057..5734271 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -18,7 +18,6 @@
 
 import static android.content.om.OverlayInfo.STATE_DISABLED;
 import static android.content.om.OverlayInfo.STATE_ENABLED;
-import static android.content.om.OverlayInfo.STATE_ENABLED_IMMUTABLE;
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
 import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
 import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED;
@@ -806,11 +805,4 @@
          **/
         void onOverlaysChanged(@NonNull String targetPackage, int userId);
     }
-
-    interface PackageManagerHelper {
-        PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-        boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2,
-                                   int userId);
-        List<PackageInfo> getOverlayPackages(int userId);
-    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
new file mode 100644
index 0000000..6b81884
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
@@ -0,0 +1,85 @@
+/*
+ * 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.om;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayableInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Delegate to the system for querying information about overlayables and packages.
+ */
+public interface OverlayableInfoCallback {
+
+    /**
+     * Read from the APK and AndroidManifest of a package to return the overlayable defined for
+     * a given name.
+     *
+     * @throws IOException if the target can't be read
+     */
+    @Nullable
+    OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+            @NonNull String targetOverlayableName, int userId)
+            throws IOException;
+
+    /**
+     * @see PackageManager#getPackagesForUid(int)
+     */
+    @Nullable
+    String[] getPackagesForUid(int uid);
+
+    /**
+     * @param userId user to filter package visibility by
+     * @see PackageManager#getPackageInfo(String, int)
+     */
+    @Nullable
+    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+
+    /**
+     * @return map of system pre-defined, uniquely named actors; keys are namespace,
+     * value maps actor name to package name
+     */
+    @NonNull
+    Map<String, Map<String, String>> getNamedActors();
+
+    /**
+     * @return true if the target package has declared an overlayable
+     */
+    boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
+            throws RemoteException, IOException;
+
+    /**
+     * @throws SecurityException containing message if the caller doesn't have the given
+     *                           permission
+     */
+    void enforcePermission(String permission, String message) throws SecurityException;
+
+    /**
+     * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
+     *     in the system returns {@link PackageManager#SIGNATURE_MATCH}
+     */
+    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+}
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
new file mode 100644
index 0000000..ec9c5e6
--- /dev/null
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -0,0 +1,36 @@
+/*
+ * 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.om;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+
+import java.util.List;
+
+/**
+ * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality,
+ * separated for easy testing.
+ *
+ * @hide
+ */
+interface PackageManagerHelper {
+    PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+    boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+    List<PackageInfo> getOverlayPackages(int userId);
+}
diff --git a/services/core/java/com/android/server/people/PeopleServiceInternal.java b/services/core/java/com/android/server/people/PeopleServiceInternal.java
index 31fa4d1..8b4740b 100644
--- a/services/core/java/com/android/server/people/PeopleServiceInternal.java
+++ b/services/core/java/com/android/server/people/PeopleServiceInternal.java
@@ -17,6 +17,7 @@
 package com.android.server.people;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.os.CancellationSignal;
 import android.service.appprediction.IPredictionService;
@@ -34,16 +35,17 @@
             @NonNull CancellationSignal signal);
 
     /**
-     * The number conversation infos will be dynamic, based on the currently installed apps on the
-     * device. All of which should be combined into a single blob to be backed up.
+     * Returns a backup payload that contains conversation infos. The number conversation infos will
+     * be dynamic, based on the currently installed apps on the device. All of which should be
+     * combined into a single blob to be backed up.
      */
-    public abstract byte[] backupConversationInfos(@UserIdInt int userId);
+    @Nullable
+    public abstract byte[] getBackupPayload(@UserIdInt int userId);
 
     /**
-     * Multiple conversation infos may exist in the restore payload, child classes are required to
-     * manage the restoration based on how individual conversation infos were originally combined
-     * during backup.
+     * Restores conversation infos stored in payload blob. Multiple conversation infos may exist in
+     * the restore payload, child classes are required to manage the restoration based on how
+     * individual conversation infos were originally combined during backup.
      */
-    public abstract void restoreConversationInfos(@UserIdInt int userId, @NonNull String key,
-            @NonNull byte[] payload);
+    public abstract void restore(@UserIdInt int userId, @NonNull byte[] payload);
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f714af03..74cb93d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11780,14 +11780,22 @@
         final String pkgName = pkg.getPackageName();
         if (mCustomResolverComponentName != null &&
                 mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
-            setUpCustomResolverActivity(pkg);
+            setUpCustomResolverActivity(pkg, pkgSetting);
         }
 
         if (pkg.getPackageName().equals("android")) {
             synchronized (mLock) {
                 // Set up information for our fall-back user intent resolution activity.
                 mPlatformPackage = pkg;
+
+                // The instance stored in PackageManagerService is special cased to be non-user
+                // specific, so initialize all the needed fields here.
                 mAndroidApplication = pkg.toAppInfoWithoutState();
+                mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
+                mAndroidApplication.privateFlags =
+                        PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
+                mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);
+
                 if (!mResolverReplaced) {
                     mResolveActivity.applicationInfo = mAndroidApplication;
                     mResolveActivity.name = ResolverActivity.class.getName();
@@ -11949,11 +11957,20 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private void setUpCustomResolverActivity(AndroidPackage pkg) {
+    private void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) {
         synchronized (mLock) {
             mResolverReplaced = true;
+
+            // The instance created in PackageManagerService is special cased to be non-user
+            // specific, so initialize all the needed fields here.
+            ApplicationInfo appInfo = pkg.toAppInfoWithoutState();
+            appInfo.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
+            appInfo.privateFlags =
+                    PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
+            appInfo.initForUser(UserHandle.USER_SYSTEM);
+
             // Set up information for custom user intent resolution activity.
-            mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
+            mResolveActivity.applicationInfo = appInfo;
             mResolveActivity.name = mCustomResolverComponentName.getClassName();
             mResolveActivity.packageName = pkg.getPackageName();
             mResolveActivity.processName = pkg.getProcessName();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2453318..fa1da27 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -33,6 +33,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.compat.ChangeIdStateCache;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -441,6 +442,7 @@
 
     private static void invalidatePackageCache() {
         PackageManager.invalidatePackageInfoCache();
+        ChangeIdStateCache.invalidate();
     }
 
     PackageSetting getPackageLPr(String pkgName) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 48dd9e6..2feddb6 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -733,7 +733,7 @@
         if (!TextUtils.isEmpty(contentCapturePackageName)) {
             grantPermissionsToSystemPackage(contentCapturePackageName, userId,
                     PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
-                    CONTACTS_PERMISSIONS);
+                    CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
         }
 
         // Atthention Service
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f647b6a..4a85027 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4471,6 +4471,9 @@
         @Override
         public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
             synchronized (mLock) {
+                if (delegate != null || mCheckPermissionDelegate != null) {
+                    PackageManager.invalidatePackageInfoCache();
+                }
                 mCheckPermissionDelegate = delegate;
             }
         }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8483c77..e6c23b6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4213,15 +4213,15 @@
                                     .SCREEN_BRIGHTNESS_SETTING_LIMITS);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
-                            .SETTING_MINIMUM,
+                            .SETTING_MINIMUM_FLOAT,
                     mScreenBrightnessSettingMinimum);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
-                            .SETTING_MAXIMUM,
+                            .SETTING_MAXIMUM_FLOAT,
                     mScreenBrightnessSettingMaximum);
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
-                            .SETTING_DEFAULT,
+                            .SETTING_DEFAULT_FLOAT,
                     mScreenBrightnessSettingDefault);
             proto.end(screenBrightnessSettingLimitsToken);
 
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java b/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java
new file mode 100644
index 0000000..f9aa009
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java
@@ -0,0 +1,32 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+
+import java.io.PrintWriter;
+
+/**
+ * An interface of an object that can generate a dump.
+ */
+interface Dumpable {
+    /**
+     * Generate a human-readable dump into the given writer.
+     * @param pw The writer.
+     */
+    void dump(@NonNull PrintWriter pw);
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
new file mode 100644
index 0000000..7f047f8
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
@@ -0,0 +1,249 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A collection of pretty-print utilities for data objects.
+ */
+class ObjectPrinter {
+    /** Default maximum elements to print in a collection. */
+    static public final int kDefaultMaxCollectionLength = 16;
+
+    /**
+     * Simple version of {@link #print(Object, boolean, int)} that prints an object, without
+     * recursing into sub-objects.
+     *
+     * @param obj The object to print.
+     * @return A string representing the object.
+     */
+    static String print(@Nullable Object obj) {
+        return print(obj, false, kDefaultMaxCollectionLength);
+    }
+
+    /**
+     * Pretty-prints an object.
+     *
+     * @param obj                 The object to print.
+     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
+     *                            with {@link Object#toString()}).
+     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
+     *                            print.
+     * @return A string representing the object.
+     */
+    static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) {
+        StringBuilder builder = new StringBuilder();
+        print(builder, obj, deep, maxCollectionLength);
+        return builder.toString();
+    }
+
+    /**
+     * This version is suitable for use inside a toString() override of an object, e.g.:
+     * <pre><code>
+     *     class MyObject {
+     *         ...
+     *         @Override
+     *         String toString() {
+     *             return ObjectPrinter.printPublicFields(this, ...);
+     *         }
+     *     }
+     * </code></pre>
+     *
+     * @param obj                 The object to print.
+     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
+     *                            with {@link Object#toString()}).
+     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
+     *                            print.
+     */
+    static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) {
+        StringBuilder builder = new StringBuilder();
+        printPublicFields(builder, obj, deep, maxCollectionLength);
+        return builder.toString();
+    }
+
+    /**
+     * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}.
+     *
+     * @param builder             StringBuilder to print into.
+     * @param obj                 The object to print.
+     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
+     *                            with {@link Object#toString()}).
+     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
+     *                            print.
+     */
+    static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep,
+            int maxCollectionLength) {
+        try {
+            if (obj == null) {
+                builder.append("null");
+                return;
+            }
+            if (obj instanceof Boolean) {
+                builder.append(obj.toString());
+                return;
+            }
+            if (obj instanceof Number) {
+                builder.append(obj.toString());
+                return;
+            }
+            if (obj instanceof Character) {
+                builder.append('\'');
+                builder.append(obj.toString());
+                builder.append('\'');
+                return;
+            }
+            if (obj instanceof String) {
+                builder.append('"');
+                builder.append(obj.toString());
+                builder.append('"');
+                return;
+            }
+
+            Class cls = obj.getClass();
+
+            if (Collection.class.isAssignableFrom(cls)) {
+                Collection collection = (Collection) obj;
+                builder.append("[ ");
+                int length = collection.size();
+                boolean isLong = false;
+                int i = 0;
+                for (Object child : collection) {
+                    if (i > 0) {
+                        builder.append(", ");
+                    }
+                    if (i >= maxCollectionLength) {
+                        isLong = true;
+                        break;
+                    }
+                    print(builder, child, deep, maxCollectionLength);
+                    ++i;
+                }
+                if (isLong) {
+                    builder.append("... (+");
+                    builder.append(length - maxCollectionLength);
+                    builder.append(" entries)");
+                }
+                builder.append(" ]");
+                return;
+            }
+
+            if (Map.class.isAssignableFrom(cls)) {
+                Map<?, ?> map = (Map<?, ?>) obj;
+                builder.append("< ");
+                int length = map.size();
+                boolean isLong = false;
+                int i = 0;
+                for (Map.Entry<?, ?> child : map.entrySet()) {
+                    if (i > 0) {
+                        builder.append(", ");
+                    }
+                    if (i >= maxCollectionLength) {
+                        isLong = true;
+                        break;
+                    }
+                    print(builder, child.getKey(), deep, maxCollectionLength);
+                    builder.append(": ");
+                    print(builder, child.getValue(), deep, maxCollectionLength);
+                    ++i;
+                }
+                if (isLong) {
+                    builder.append("... (+");
+                    builder.append(length - maxCollectionLength);
+                    builder.append(" entries)");
+                }
+                builder.append(" >");
+                return;
+            }
+
+            if (cls.isArray()) {
+                builder.append("[ ");
+                int length = Array.getLength(obj);
+                boolean isLong = false;
+                for (int i = 0; i < length; ++i) {
+                    if (i > 0) {
+                        builder.append(", ");
+                    }
+                    if (i >= maxCollectionLength) {
+                        isLong = true;
+                        break;
+                    }
+                    print(builder, Array.get(obj, i), deep, maxCollectionLength);
+                }
+                if (isLong) {
+                    builder.append("... (+");
+                    builder.append(length - maxCollectionLength);
+                    builder.append(" entries)");
+                }
+                builder.append(" ]");
+                return;
+            }
+
+            if (!deep) {
+                builder.append(obj.toString());
+                return;
+            }
+            printPublicFields(builder, obj, deep, maxCollectionLength);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link
+     * StringBuilder}.
+     *
+     * @param obj                 The object to print.
+     * @param deep                Whether to pretty-print sub-objects (if false, just prints them
+     *                            with {@link Object#toString()}).
+     * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
+     *                            print.
+     */
+    static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj,
+            boolean deep,
+            int maxCollectionLength) {
+        try {
+            Class cls = obj.getClass();
+            builder.append("{ ");
+
+            boolean first = true;
+            for (Field fld : cls.getDeclaredFields()) {
+                int mod = fld.getModifiers();
+                if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        builder.append(", ");
+                    }
+                    builder.append(fld.getName());
+                    builder.append(": ");
+                    print(builder, fld.get(obj), deep, maxCollectionLength);
+                }
+            }
+            builder.append(" }");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
new file mode 100644
index 0000000..fa78cb0
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -0,0 +1,454 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.soundtrigger_middleware.ISoundTriggerCallback;
+import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
+import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.ModelParameterRange;
+import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.PhraseSoundModel;
+import android.media.soundtrigger_middleware.RecognitionConfig;
+import android.media.soundtrigger_middleware.RecognitionEvent;
+import android.media.soundtrigger_middleware.SoundModel;
+import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.LinkedList;
+
+/**
+ * An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and
+ * callbacks).
+ *
+ * All API methods should follow this structure:
+ * <pre><code>
+ * @Override
+ * public @NonNull ReturnType someMethod(ArgType1 arg1, ArgType2 arg2) throws ExceptionType {
+ *     try {
+ *         ReturnType result = mDelegate.someMethod(arg1, arg2);
+ *         logReturn("someMethod", result, arg1, arg2);
+ *         return result;
+ *     } catch (Exception e) {
+ *         logException("someMethod", e, arg1, arg2);
+ *         throw e;
+ *     }
+ * }
+ * </code></pre>
+ * The actual handling of these events is then done inside of {@link #logReturnWithObject(Object,
+ * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link
+ * #logExceptionWithObject(Object, String, Exception, Object[])}.
+ */
+public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService, Dumpable {
+    private static final String TAG = "SoundTriggerMiddlewareLogging";
+    private final @NonNull ISoundTriggerMiddlewareService mDelegate;
+
+    public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareService delegate) {
+        mDelegate = delegate;
+    }
+
+    @Override
+    public @NonNull SoundTriggerModuleDescriptor[] listModules() throws RemoteException {
+        try {
+            SoundTriggerModuleDescriptor[] result = mDelegate.listModules();
+            logReturn("listModules", result);
+            return result;
+        } catch (Exception e) {
+            logException("listModules", e);
+            throw e;
+        }
+    }
+
+    @Override
+    public @NonNull ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback)
+            throws RemoteException {
+        try {
+            ISoundTriggerModule result = mDelegate.attach(handle, new CallbackLogging(callback));
+            logReturn("attach", result, handle, callback);
+            return new ModuleLogging(result);
+        } catch (Exception e) {
+            logException("attach", e, handle, callback);
+            throw e;
+        }
+    }
+
+    @Override
+    public void setExternalCaptureState(boolean active) throws RemoteException {
+        try {
+            mDelegate.setExternalCaptureState(active);
+            logVoidReturn("setExternalCaptureState", active);
+        } catch (Exception e) {
+            logException("setExternalCaptureState", e, active);
+            throw e;
+        }
+    }
+
+    @Override public IBinder asBinder() {
+        throw new UnsupportedOperationException(
+                "This implementation is not inteded to be used directly with Binder.");
+    }
+
+    // Override toString() in order to have the delegate's ID in it.
+    @Override
+    public String toString() {
+        return mDelegate.toString();
+    }
+
+    private void logException(String methodName, Exception ex, Object... args) {
+        logExceptionWithObject(this, methodName, ex, args);
+    }
+
+    private void logReturn(String methodName, Object retVal, Object... args) {
+        logReturnWithObject(this, methodName, retVal, args);
+    }
+
+    private void logVoidReturn(String methodName, Object... args) {
+        logVoidReturnWithObject(this, methodName, args);
+    }
+
+    private class CallbackLogging implements ISoundTriggerCallback {
+        private final ISoundTriggerCallback mDelegate;
+
+        private CallbackLogging(ISoundTriggerCallback delegate) {
+            mDelegate = delegate;
+        }
+
+        @Override
+        public void onRecognition(int modelHandle, RecognitionEvent event) throws RemoteException {
+            try {
+                mDelegate.onRecognition(modelHandle, event);
+                logVoidReturn("onRecognition", modelHandle, event);
+            } catch (Exception e) {
+                logException("onRecognition", e, modelHandle, event);
+                throw e;
+            }
+        }
+
+        @Override
+        public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event)
+                throws RemoteException {
+            try {
+                mDelegate.onPhraseRecognition(modelHandle, event);
+                logVoidReturn("onPhraseRecognition", modelHandle, event);
+            } catch (Exception e) {
+                logException("onPhraseRecognition", e, modelHandle, event);
+                throw e;
+            }
+        }
+
+        @Override
+        public void onRecognitionAvailabilityChange(boolean available) throws RemoteException {
+            try {
+                mDelegate.onRecognitionAvailabilityChange(available);
+                logVoidReturn("onRecognitionAvailabilityChange", available);
+            } catch (Exception e) {
+                logException("onRecognitionAvailabilityChange", e, available);
+                throw e;
+            }
+        }
+
+        @Override
+        public void onModuleDied() throws RemoteException {
+            try {
+                mDelegate.onModuleDied();
+                logVoidReturn("onModuleDied");
+            } catch (Exception e) {
+                logException("onModuleDied", e);
+                throw e;
+            }
+        }
+
+        private void logException(String methodName, Exception ex, Object... args) {
+            logExceptionWithObject(this, methodName, ex, args);
+        }
+
+        private void logVoidReturn(String methodName, Object... args) {
+            logVoidReturnWithObject(this, methodName, args);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return mDelegate.asBinder();
+        }
+
+        // Override toString() in order to have the delegate's ID in it.
+        @Override
+        public String toString() {
+            return mDelegate.toString();
+        }
+    }
+
+    private class ModuleLogging implements ISoundTriggerModule {
+        private final ISoundTriggerModule mDelegate;
+
+        private ModuleLogging(ISoundTriggerModule delegate) {
+            mDelegate = delegate;
+        }
+
+        @Override
+        public int loadModel(SoundModel model) throws RemoteException {
+            try {
+                int result = mDelegate.loadModel(model);
+                logReturn("loadModel", result, model);
+                return result;
+            } catch (Exception e) {
+                logException("loadModel", e, model);
+                throw e;
+            }
+        }
+
+        @Override
+        public int loadPhraseModel(PhraseSoundModel model) throws RemoteException {
+            try {
+                int result = mDelegate.loadPhraseModel(model);
+                logReturn("loadPhraseModel", result, model);
+                return result;
+            } catch (Exception e) {
+                logException("loadPhraseModel", e, model);
+                throw e;
+            }
+        }
+
+        @Override
+        public void unloadModel(int modelHandle) throws RemoteException {
+            try {
+                mDelegate.unloadModel(modelHandle);
+                logVoidReturn("unloadModel", modelHandle);
+            } catch (Exception e) {
+                logException("unloadModel", e, modelHandle);
+                throw e;
+            }
+        }
+
+        @Override
+        public void startRecognition(int modelHandle, RecognitionConfig config)
+                throws RemoteException {
+            try {
+                mDelegate.startRecognition(modelHandle, config);
+                logVoidReturn("startRecognition", modelHandle, config);
+            } catch (Exception e) {
+                logException("startRecognition", e, modelHandle, config);
+                throw e;
+            }
+        }
+
+        @Override
+        public void stopRecognition(int modelHandle) throws RemoteException {
+            try {
+                mDelegate.stopRecognition(modelHandle);
+                logVoidReturn("stopRecognition", modelHandle);
+            } catch (Exception e) {
+                logException("stopRecognition", e, modelHandle);
+                throw e;
+            }
+        }
+
+        @Override
+        public void forceRecognitionEvent(int modelHandle) throws RemoteException {
+            try {
+                mDelegate.forceRecognitionEvent(modelHandle);
+                logVoidReturn("forceRecognitionEvent", modelHandle);
+            } catch (Exception e) {
+                logException("forceRecognitionEvent", e, modelHandle);
+                throw e;
+            }
+        }
+
+        @Override
+        public void setModelParameter(int modelHandle, int modelParam, int value)
+                throws RemoteException {
+            try {
+                mDelegate.setModelParameter(modelHandle, modelParam, value);
+                logVoidReturn("setModelParameter", modelHandle, modelParam, value);
+            } catch (Exception e) {
+                logException("setModelParameter", e, modelHandle, modelParam, value);
+                throw e;
+            }
+        }
+
+        @Override
+        public int getModelParameter(int modelHandle, int modelParam) throws RemoteException {
+            try {
+                int result = mDelegate.getModelParameter(modelHandle, modelParam);
+                logReturn("getModelParameter", result, modelHandle, modelParam);
+                return result;
+            } catch (Exception e) {
+                logException("getModelParameter", e, modelHandle, modelParam);
+                throw e;
+            }
+        }
+
+        @Override
+        public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam)
+                throws RemoteException {
+            try {
+                ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
+                        modelParam);
+                logReturn("queryModelParameterSupport", result, modelHandle, modelParam);
+                return result;
+            } catch (Exception e) {
+                logException("queryModelParameterSupport", e, modelHandle, modelParam);
+                throw e;
+            }
+        }
+
+        @Override
+        public void detach() throws RemoteException {
+            try {
+                mDelegate.detach();
+                logVoidReturn("detach");
+            } catch (Exception e) {
+                logException("detach", e);
+                throw e;
+            }
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return mDelegate.asBinder();
+        }
+
+        // Override toString() in order to have the delegate's ID in it.
+        @Override
+        public String toString() {
+            return mDelegate.toString();
+        }
+
+        private void logException(String methodName, Exception ex, Object... args) {
+            logExceptionWithObject(this, methodName, ex, args);
+        }
+
+        private void logReturn(String methodName, Object retVal, Object... args) {
+            logReturnWithObject(this, methodName, retVal, args);
+        }
+
+        private void logVoidReturn(String methodName, Object... args) {
+            logVoidReturnWithObject(this, methodName, args);
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // Actual logging logic below.
+    private static final int NUM_EVENTS_TO_DUMP = 64;
+    private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+    private final @NonNull LinkedList<Event> mLastEvents = new LinkedList<>();
+
+    static private class Event {
+        public final long timestamp = System.currentTimeMillis();
+        public final String message;
+
+        private Event(String message) {
+            this.message = message;
+        }
+    }
+
+    private static String printArgs(@NonNull Object[] args) {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < args.length; ++i) {
+            if (i > 0) {
+                result.append(", ");
+            }
+            printObject(result, args[i]);
+        }
+        return result.toString();
+    }
+
+    private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) {
+        if (obj instanceof Parcelable) {
+            ObjectPrinter.print(builder, obj, true, 16);
+        } else {
+            builder.append(obj.toString());
+        }
+    }
+
+    private static String printObject(@Nullable Object obj) {
+        StringBuilder builder = new StringBuilder();
+        printObject(builder, obj);
+        return builder.toString();
+    }
+
+    private void logReturnWithObject(@NonNull Object object, String methodName,
+            @Nullable Object retVal,
+            @NonNull Object[] args) {
+        final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName,
+                object,
+                Binder.getCallingUid(), Binder.getCallingPid(),
+                printArgs(args),
+                printObject(retVal));
+        Log.i(TAG, message);
+        appendMessage(message);
+    }
+
+    private void logVoidReturnWithObject(@NonNull Object object, @NonNull String methodName,
+            @NonNull Object[] args) {
+        final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName,
+                object,
+                Binder.getCallingUid(), Binder.getCallingPid(),
+                printArgs(args));
+        Log.i(TAG, message);
+        appendMessage(message);
+    }
+
+    private void logExceptionWithObject(@NonNull Object object, @NonNull String methodName,
+            @NonNull Exception ex,
+            Object[] args) {
+        final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName,
+                object,
+                Binder.getCallingUid(), Binder.getCallingPid(),
+                printArgs(args));
+        Log.e(TAG, message, ex);
+        appendMessage(message + " " + ex.toString());
+    }
+
+    private void appendMessage(@NonNull String message) {
+        Event event = new Event(message);
+        synchronized (mLastEvents) {
+            if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) {
+                mLastEvents.remove();
+            }
+            mLastEvents.add(event);
+        }
+    }
+
+    @Override public void dump(PrintWriter pw) {
+        pw.println();
+        pw.println("=========================================");
+        pw.println("Last events");
+        pw.println("=========================================");
+        synchronized (mLastEvents) {
+            for (Event event : mLastEvents) {
+                pw.print(DATE_FORMAT.format(new Date(event.timestamp)));
+                pw.print('\t');
+                pw.println(event.message);
+            }
+        }
+        pw.println();
+
+        if (mDelegate instanceof Dumpable) {
+            ((Dumpable) mDelegate).dump(pw);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index 1ed97be..0d8fc76 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -16,91 +16,40 @@
 
 package com.android.server.soundtrigger_middleware;
 
-import android.Manifest;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
-import android.content.PermissionChecker;
 import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
 import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
 import android.media.soundtrigger_middleware.PhraseSoundModel;
 import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionStatus;
 import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.Status;
 import android.os.RemoteException;
-import android.os.ServiceSpecificException;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * This is a wrapper around an {@link ISoundTriggerMiddlewareService} implementation, which exposes
- * it as a Binder service and enforces permissions and correct usage by the client, as well as makes
- * sure that exceptions representing a server malfunction do not get sent to the client.
+ * it as a Binder service.
  * <p>
- * This is intended to extract the non-business logic out of the underlying implementation and thus
- * make it easier to maintain each one of those separate aspects. A design trade-off is being made
- * here, in that this class would need to essentially eavesdrop on all the client-server
- * communication and retain all state known to the client, while the client doesn't necessarily care
- * about all of it, and while the server has its own representation of this information. However,
- * in this case, this is a small amount of data, and the benefits in code elegance seem worth it.
- * There is also some additional cost in employing a simplistic locking mechanism here, but
- * following the same line of reasoning, the benefits in code simplicity outweigh it.
+ * This is intended to facilitate a pattern of decorating the core implementation (business logic)
+ * of the interface with every decorator implementing a different aspect of the service, such as
+ * validation and logging. This class acts as the top-level decorator, which also adds the binder-
+ * related functionality (hence, it extends ISoundTriggerMiddlewareService.Stub as rather than
+ * implements ISoundTriggerMiddlewareService), and does the same thing for child interfaces
+ * returned.
  * <p>
- * Every public method in this class, overriding an interface method, must follow the following
- * pattern:
- * <code><pre>
- * @Override public T method(S arg) {
- *     // Permission check.
- *     checkPermissions();
- *     // Input validation.
- *     ValidationUtil.validateS(arg);
- *     synchronized (this) {
- *         // State validation.
- *         if (...state is not valid for this call...) {
- *             throw new IllegalStateException("State is invalid because...");
- *         }
- *         // From here on, every exception isn't client's fault.
- *         try {
- *             T result = mDelegate.method(arg);
- *             // Update state.;
- *             ...
- *             return result;
- *         } catch (Exception e) {
- *             throw handleException(e);
- *         }
- *     }
- * }
- * </pre></code>
- * Following this patterns ensures a consistent and rigorous handling of all aspects associated
- * with client-server separation.
- * <p>
- * <b>Exception handling approach:</b><br>
- * We make sure all client faults (permissions, argument and state validation) happen first, and
- * would throw {@link SecurityException}, {@link IllegalArgumentException}/
- * {@link NullPointerException} or {@link
- * IllegalStateException}, respectively. All those exceptions are treated specially by Binder and
- * will get sent back to the client.<br>
- * Once this is done, any subsequent fault is considered a server fault. Only {@link
- * RecoverableException}s thrown by the implementation are special-cased: they would get sent back
- * to the caller as a {@link ServiceSpecificException}, which is the behavior of Binder. Any other
- * exception gets wrapped with a {@link InternalServerError}, which is specifically chosen as a type
- * that <b>does NOT</b> get forwarded by binder. Those exceptions would be handled by a high-level
- * exception handler on the server side, typically resulting in rebooting the server.
+ * The inner class {@link Lifecycle} acts as both a factory, composing the various aspect-decorators
+ * to create a full-featured implementation, as well as as an entry-point for presenting this
+ * implementation as a system service.
  * <p>
  * <b>Exposing this service as a System Service:</b><br>
  * Insert this line into {@link com.android.server.SystemServer}:
@@ -113,224 +62,100 @@
 public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareService.Stub {
     static private final String TAG = "SoundTriggerMiddlewareService";
 
+    @NonNull
     private final ISoundTriggerMiddlewareService mDelegate;
-    private final Context mContext;
-    private Set<Integer> mModuleHandles;
 
     /**
      * Constructor for internal use only. Could be exposed for testing purposes in the future.
      * Users should access this class via {@link Lifecycle}.
      */
-    private SoundTriggerMiddlewareService(
-            @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) {
-        mDelegate = delegate;
-        mContext = context;
-    }
-
-    /**
-     * Generic exception handling for exceptions thrown by the underlying implementation.
-     *
-     * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed
-     * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError}
-     * (<b>not</b> passed by Binder to the caller).
-     * <p>
-     * Typical usage:
-     * <code><pre>
-     * try {
-     *     ... Do server operations ...
-     * } catch (Exception e) {
-     *     throw handleException(e);
-     * }
-     * </pre></code>
-     */
-    private static @NonNull
-    RuntimeException handleException(@NonNull Exception e) {
-        if (e instanceof RecoverableException) {
-            throw new ServiceSpecificException(((RecoverableException) e).errorCode,
-                    e.getMessage());
-        }
-        throw new InternalServerError(e);
+    private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareService delegate) {
+        mDelegate = Objects.requireNonNull(delegate);
     }
 
     @Override
     public @NonNull
-    SoundTriggerModuleDescriptor[] listModules() {
-        // Permission check.
-        checkPermissions();
-        // Input validation (always valid).
-
-        synchronized (this) {
-            // State validation (always valid).
-
-            // From here on, every exception isn't client's fault.
-            try {
-                SoundTriggerModuleDescriptor[] result = mDelegate.listModules();
-                mModuleHandles = new HashSet<>(result.length);
-                for (SoundTriggerModuleDescriptor desc : result) {
-                    mModuleHandles.add(desc.handle);
-                }
-                return result;
-            } catch (Exception e) {
-                throw handleException(e);
-            }
-        }
+    SoundTriggerModuleDescriptor[] listModules() throws RemoteException {
+        return mDelegate.listModules();
     }
 
     @Override
     public @NonNull
-    ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) {
-        // Permission check.
-        checkPermissions();
-        // Input validation.
-        Objects.requireNonNull(callback);
-        Objects.requireNonNull(callback.asBinder());
-
-        synchronized (this) {
-            // State validation.
-            if (mModuleHandles == null) {
-                throw new IllegalStateException(
-                        "Client must call listModules() prior to attaching.");
-            }
-            if (!mModuleHandles.contains(handle)) {
-                throw new IllegalArgumentException("Invalid handle: " + handle);
-            }
-
-            // From here on, every exception isn't client's fault.
-            try {
-                ModuleService moduleService = new ModuleService(callback);
-                moduleService.attach(mDelegate.attach(handle, moduleService));
-                return moduleService;
-            } catch (Exception e) {
-                throw handleException(e);
-            }
-        }
+    ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback)
+            throws RemoteException {
+        return new ModuleService(mDelegate.attach(handle, callback));
     }
 
     @Override
-    public void setExternalCaptureState(boolean active) {
-        // Permission check.
-        checkPreemptPermissions();
-        // Input validation (always valid).
+    public void setExternalCaptureState(boolean active) throws RemoteException {
+        mDelegate.setExternalCaptureState(active);
+    }
 
-        synchronized (this) {
-            // State validation (always valid).
-
-            // From here on, every exception isn't client's fault.
-            try {
-                mDelegate.setExternalCaptureState(active);
-            } catch (Exception e) {
-                throw handleException(e);
-            }
+    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        if (mDelegate instanceof Dumpable) {
+            ((Dumpable) mDelegate).dump(fout);
         }
     }
 
-    /**
-     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
-     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
-     * caller temporarily doesn't have the right permissions to use this service.
-     */
-    private void checkPermissions() {
-        enforcePermission(Manifest.permission.RECORD_AUDIO);
-        enforcePermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
-    }
+    private final static class ModuleService extends ISoundTriggerModule.Stub {
+        private final ISoundTriggerModule mDelegate;
 
-    /**
-     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
-     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
-     * caller temporarily doesn't have the right permissions to preempt active sound trigger
-     * sessions.
-     */
-    private void checkPreemptPermissions() {
-        enforcePermission(Manifest.permission.PREEMPT_SOUND_TRIGGER);
-    }
-
-    /**
-     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
-     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
-     * caller temporarily doesn't have the given permission.
-     *
-     * @param permission The permission to check.
-     */
-    private void enforcePermission(String permission) {
-        final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext,
-                permission);
-        switch (status) {
-            case PermissionChecker.PERMISSION_GRANTED:
-                return;
-            case PermissionChecker.PERMISSION_HARD_DENIED:
-                throw new SecurityException(
-                        String.format("Caller must have the %s permission.", permission));
-            case PermissionChecker.PERMISSION_SOFT_DENIED:
-                throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
-                        String.format("Caller must have the %s permission.", permission));
-            default:
-                throw new InternalServerError(
-                        new RuntimeException("Unexpected perimission check result."));
-        }
-    }
-
-    /** State of a sound model. */
-    static class ModelState {
-        /** Activity state of a sound model. */
-        enum Activity {
-            /** Model is loaded, recognition is inactive. */
-            LOADED,
-            /** Model is loaded, recognition is active. */
-            ACTIVE
+        private ModuleService(ISoundTriggerModule delegate) {
+            mDelegate = delegate;
         }
 
-        /** Activity state. */
-        Activity activityState = Activity.LOADED;
-
-        /**
-         * A map of known parameter support. A missing key means we don't know yet whether the
-         * parameter is supported. A null value means it is known to not be supported. A non-null
-         * value indicates the valid value range.
-         */
-        private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();
-
-        /**
-         * Check that the given parameter is known to be supported for this model.
-         *
-         * @param modelParam The parameter key.
-         */
-        void checkSupported(int modelParam) {
-            if (!parameterSupport.containsKey(modelParam)) {
-                throw new IllegalStateException("Parameter has not been checked for support.");
-            }
-            ModelParameterRange range = parameterSupport.get(modelParam);
-            if (range == null) {
-                throw new IllegalArgumentException("Paramater is not supported.");
-            }
+        @Override
+        public int loadModel(SoundModel model) throws RemoteException {
+            return mDelegate.loadModel(model);
         }
 
-        /**
-         * Check that the given parameter is known to be supported for this model and that the given
-         * value is a valid value for it.
-         *
-         * @param modelParam The parameter key.
-         * @param value      The value.
-         */
-        void checkSupported(int modelParam, int value) {
-            if (!parameterSupport.containsKey(modelParam)) {
-                throw new IllegalStateException("Parameter has not been checked for support.");
-            }
-            ModelParameterRange range = parameterSupport.get(modelParam);
-            if (range == null) {
-                throw new IllegalArgumentException("Paramater is not supported.");
-            }
-            Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive,
-                    "value");
+        @Override
+        public int loadPhraseModel(PhraseSoundModel model) throws RemoteException {
+            return mDelegate.loadPhraseModel(model);
         }
 
-        /**
-         * Update support state for the given parameter for this model.
-         *
-         * @param modelParam The parameter key.
-         * @param range      The parameter value range, or null if not supported.
-         */
-        void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) {
-            parameterSupport.put(modelParam, range);
+        @Override
+        public void unloadModel(int modelHandle) throws RemoteException {
+            mDelegate.unloadModel(modelHandle);
+            ;
+        }
+
+        @Override
+        public void startRecognition(int modelHandle, RecognitionConfig config)
+                throws RemoteException {
+            mDelegate.startRecognition(modelHandle, config);
+        }
+
+        @Override
+        public void stopRecognition(int modelHandle) throws RemoteException {
+            mDelegate.stopRecognition(modelHandle);
+        }
+
+        @Override
+        public void forceRecognitionEvent(int modelHandle) throws RemoteException {
+            mDelegate.forceRecognitionEvent(modelHandle);
+        }
+
+        @Override
+        public void setModelParameter(int modelHandle, int modelParam, int value)
+                throws RemoteException {
+            mDelegate.setModelParameter(modelHandle, modelParam, value);
+        }
+
+        @Override
+        public int getModelParameter(int modelHandle, int modelParam) throws RemoteException {
+            return mDelegate.getModelParameter(modelHandle, modelParam);
+        }
+
+        @Override
+        public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam)
+                throws RemoteException {
+            return mDelegate.queryModelParameterSupport(modelHandle, modelParam);
+        }
+
+        @Override
+        public void detach() throws RemoteException {
+            mDelegate.detach();
         }
     }
 
@@ -355,395 +180,11 @@
 
             publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE,
                     new SoundTriggerMiddlewareService(
-                            new SoundTriggerMiddlewareImpl(factories,
-                                    new AudioSessionProviderImpl()),
-                            getContext()));
-        }
-    }
-
-    /**
-     * A wrapper around an {@link ISoundTriggerModule} implementation, to address the same aspects
-     * mentioned in {@link SoundTriggerModule} above. This class follows the same conventions.
-     */
-    private class ModuleService extends ISoundTriggerModule.Stub implements ISoundTriggerCallback,
-            DeathRecipient {
-        private final ISoundTriggerCallback mCallback;
-        private ISoundTriggerModule mDelegate;
-        private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>();
-
-        ModuleService(@NonNull ISoundTriggerCallback callback) {
-            mCallback = callback;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
-            }
-        }
-
-        void attach(@NonNull ISoundTriggerModule delegate) {
-            mDelegate = delegate;
-        }
-
-        @Override
-        public int loadModel(@NonNull SoundModel model) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validateGenericModel(model);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    int handle = mDelegate.loadModel(model);
-                    mLoadedModels.put(handle, new ModelState());
-                    return handle;
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public int loadPhraseModel(@NonNull PhraseSoundModel model) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validatePhraseModel(model);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    int handle = mDelegate.loadPhraseModel(model);
-                    mLoadedModels.put(handle, new ModelState());
-                    return handle;
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void unloadModel(int modelHandle) {
-            // Permission check.
-            checkPermissions();
-            // Input validation (always valid).
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                if (modelState.activityState != ModelState.Activity.LOADED) {
-                    throw new IllegalStateException("Model with handle: " + modelHandle
-                            + " has invalid state for unloading: " + modelState.activityState);
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.unloadModel(modelHandle);
-                    mLoadedModels.remove(modelHandle);
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validateRecognitionConfig(config);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                if (modelState.activityState != ModelState.Activity.LOADED) {
-                    throw new IllegalStateException("Model with handle: " + modelHandle
-                            + " has invalid state for starting recognition: "
-                            + modelState.activityState);
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.startRecognition(modelHandle, config);
-                    modelState.activityState = ModelState.Activity.ACTIVE;
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void stopRecognition(int modelHandle) {
-            // Permission check.
-            checkPermissions();
-            // Input validation (always valid).
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                // stopRecognition is idempotent - no need to check model state.
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.stopRecognition(modelHandle);
-                    modelState.activityState = ModelState.Activity.LOADED;
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void forceRecognitionEvent(int modelHandle) {
-            // Permission check.
-            checkPermissions();
-            // Input validation (always valid).
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                // forceRecognitionEvent is idempotent - no need to check model state.
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.forceRecognitionEvent(modelHandle);
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void setModelParameter(int modelHandle, int modelParam, int value) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validateModelParameter(modelParam);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                modelState.checkSupported(modelParam, value);
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.setModelParameter(modelHandle, modelParam, value);
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public int getModelParameter(int modelHandle, int modelParam) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validateModelParameter(modelParam);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-                modelState.checkSupported(modelParam);
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    return mDelegate.getModelParameter(modelHandle, modelParam);
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        @Nullable
-        public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) {
-            // Permission check.
-            checkPermissions();
-            // Input validation.
-            ValidationUtil.validateModelParameter(modelParam);
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has been detached.");
-                }
-                ModelState modelState = mLoadedModels.get(modelHandle);
-                if (modelState == null) {
-                    throw new IllegalStateException("Invalid handle: " + modelHandle);
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
-                            modelParam);
-                    modelState.updateParameterSupport(modelParam, result);
-                    return result;
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        @Override
-        public void detach() {
-            // Permission check.
-            checkPermissions();
-            // Input validation (always valid).
-
-            synchronized (this) {
-                // State validation.
-                if (mDelegate == null) {
-                    throw new IllegalStateException("Module has already been detached.");
-                }
-                if (!mLoadedModels.isEmpty()) {
-                    throw new IllegalStateException("Cannot detach while models are loaded.");
-                }
-
-                // From here on, every exception isn't client's fault.
-                try {
-                    detachInternal();
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
-        }
-
-        private void detachInternal() {
-            try {
-                mDelegate.detach();
-                mDelegate = null;
-                mCallback.asBinder().unlinkToDeath(this, 0);
-            } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
-            }
-        }
-
-        ////////////////////////////////////////////////////////////////////////////////////////////
-        // Callbacks
-
-        @Override
-        public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) {
-            synchronized (this) {
-                if (event.status != RecognitionStatus.FORCED) {
-                    mLoadedModels.get(modelHandle).activityState = ModelState.Activity.LOADED;
-                }
-                try {
-                    mCallback.onRecognition(modelHandle, event);
-                } catch (RemoteException e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback exception.", e);
-                }
-            }
-        }
-
-        @Override
-        public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) {
-            synchronized (this) {
-                if (event.common.status != RecognitionStatus.FORCED) {
-                    mLoadedModels.get(modelHandle).activityState = ModelState.Activity.LOADED;
-                }
-                try {
-                    mCallback.onPhraseRecognition(modelHandle, event);
-                } catch (RemoteException e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback exception.", e);
-                }
-            }
-        }
-
-        @Override
-        public void onRecognitionAvailabilityChange(boolean available) {
-            synchronized (this) {
-                try {
-                    mCallback.onRecognitionAvailabilityChange(available);
-                } catch (RemoteException e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback exception.", e);
-                }
-            }
-        }
-
-        @Override
-        public void onModuleDied() {
-            synchronized (this) {
-                try {
-                    mCallback.onModuleDied();
-                } catch (RemoteException e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback exception.", e);
-                }
-            }
-        }
-
-        @Override
-        public void binderDied() {
-            // This is called whenever our client process dies.
-            synchronized (this) {
-                try {
-                    // Gracefully stop all active recognitions and unload the models.
-                    for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
-                        if (entry.getValue().activityState == ModelState.Activity.ACTIVE) {
-                            mDelegate.stopRecognition(entry.getKey());
-                        }
-                        mDelegate.unloadModel(entry.getKey());
-                    }
-                    // Detach.
-                    detachInternal();
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
-            }
+                            new SoundTriggerMiddlewareLogging(
+                                    new SoundTriggerMiddlewareValidation(
+                                            new SoundTriggerMiddlewareImpl(factories,
+                                                    new AudioSessionProviderImpl()),
+                                            getContext()))));
         }
     }
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
new file mode 100644
index 0000000..c45f37d
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -0,0 +1,784 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.PermissionChecker;
+import android.media.soundtrigger_middleware.ISoundTriggerCallback;
+import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
+import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.ModelParameterRange;
+import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.PhraseSoundModel;
+import android.media.soundtrigger_middleware.RecognitionConfig;
+import android.media.soundtrigger_middleware.RecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionStatus;
+import android.media.soundtrigger_middleware.SoundModel;
+import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
+import android.media.soundtrigger_middleware.Status;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This is a decorator of an {@link ISoundTriggerMiddlewareService}, which enforces permissions and
+ * correct usage by the client, as well as makes sure that exceptions representing a server
+ * malfunction do not get sent to the client.
+ * <p>
+ * This is intended to extract the non-business logic out of the underlying implementation and thus
+ * make it easier to maintain each one of those separate aspects. A design trade-off is being made
+ * here, in that this class would need to essentially eavesdrop on all the client-server
+ * communication and retain all state known to the client, while the client doesn't necessarily care
+ * about all of it, and while the server has its own representation of this information. However,
+ * in this case, this is a small amount of data, and the benefits in code elegance seem worth it.
+ * There is also some additional cost in employing a simplistic locking mechanism here, but
+ * following the same line of reasoning, the benefits in code simplicity outweigh it.
+ * <p>
+ * Every public method in this class, overriding an interface method, must follow the following
+ * pattern:
+ * <code><pre>
+ * @Override public T method(S arg) {
+ *     // Permission check.
+ *     checkPermissions();
+ *     // Input validation.
+ *     ValidationUtil.validateS(arg);
+ *     synchronized (this) {
+ *         // State validation.
+ *         if (...state is not valid for this call...) {
+ *             throw new IllegalStateException("State is invalid because...");
+ *         }
+ *         // From here on, every exception isn't client's fault.
+ *         try {
+ *             T result = mDelegate.method(arg);
+ *             // Update state.;
+ *             ...
+ *             return result;
+ *         } catch (Exception e) {
+ *             throw handleException(e);
+ *         }
+ *     }
+ * }
+ * </pre></code>
+ * Following this patterns ensures a consistent and rigorous handling of all aspects associated
+ * with client-server separation.
+ * <p>
+ * <b>Exception handling approach:</b><br>
+ * We make sure all client faults (permissions, argument and state validation) happen first, and
+ * would throw {@link SecurityException}, {@link IllegalArgumentException}/
+ * {@link NullPointerException} or {@link
+ * IllegalStateException}, respectively. All those exceptions are treated specially by Binder and
+ * will get sent back to the client.<br>
+ * Once this is done, any subsequent fault is considered a server fault. Only {@link
+ * RecoverableException}s thrown by the implementation are special-cased: they would get sent back
+ * to the caller as a {@link ServiceSpecificException}, which is the behavior of Binder. Any other
+ * exception gets wrapped with a {@link InternalServerError}, which is specifically chosen as a type
+ * that <b>does NOT</b> get forwarded by binder. Those exceptions would be handled by a high-level
+ * exception handler on the server side, typically resulting in rebooting the server.
+ *
+ * {@hide}
+ */
+public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService, Dumpable {
+    private static final String TAG = "SoundTriggerMiddlewareValidation";
+
+    private final @NonNull ISoundTriggerMiddlewareService mDelegate;
+    private final @NonNull Context mContext;
+    private Map<Integer, Set<ModuleService>> mModules;
+
+    public SoundTriggerMiddlewareValidation(
+            @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) {
+        mDelegate = delegate;
+        mContext = context;
+    }
+
+    /**
+     * Generic exception handling for exceptions thrown by the underlying implementation.
+     *
+     * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed
+     * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError}
+     * (<b>not</b> passed by Binder to the caller).
+     * <p>
+     * Typical usage:
+     * <code><pre>
+     * try {
+     *     ... Do server operations ...
+     * } catch (Exception e) {
+     *     throw handleException(e);
+     * }
+     * </pre></code>
+     */
+    static @NonNull
+    RuntimeException handleException(@NonNull Exception e) {
+        if (e instanceof RecoverableException) {
+            throw new ServiceSpecificException(((RecoverableException) e).errorCode,
+                    e.getMessage());
+        }
+        throw new InternalServerError(e);
+    }
+
+    @Override
+    public @NonNull
+    SoundTriggerModuleDescriptor[] listModules() {
+        // Permission check.
+        checkPermissions();
+        // Input validation (always valid).
+
+        synchronized (this) {
+            // State validation (always valid).
+
+            // From here on, every exception isn't client's fault.
+            try {
+                SoundTriggerModuleDescriptor[] result = mDelegate.listModules();
+                mModules = new HashMap<>(result.length);
+                for (SoundTriggerModuleDescriptor desc : result) {
+                    mModules.put(desc.handle, new HashSet<>());
+                }
+                return result;
+            } catch (Exception e) {
+                throw handleException(e);
+            }
+        }
+    }
+
+    @Override
+    public @NonNull ISoundTriggerModule attach(int handle,
+            @NonNull ISoundTriggerCallback callback) {
+        // Permission check.
+        checkPermissions();
+        // Input validation.
+        Objects.requireNonNull(callback);
+        Objects.requireNonNull(callback.asBinder());
+
+        synchronized (this) {
+            // State validation.
+            if (mModules == null) {
+                throw new IllegalStateException(
+                        "Client must call listModules() prior to attaching.");
+            }
+            if (!mModules.containsKey(handle)) {
+                throw new IllegalArgumentException("Invalid handle: " + handle);
+            }
+
+            // From here on, every exception isn't client's fault.
+            try {
+                ModuleService moduleService =
+                        new ModuleService(handle, callback);
+                moduleService.attach(mDelegate.attach(handle, moduleService));
+                return moduleService;
+            } catch (Exception e) {
+                throw handleException(e);
+            }
+        }
+    }
+
+    @Override
+    public void setExternalCaptureState(boolean active) {
+        // Permission check.
+        checkPreemptPermissions();
+        // Input validation (always valid).
+
+        synchronized (this) {
+            // State validation (always valid).
+
+            // From here on, every exception isn't client's fault.
+            try {
+                mDelegate.setExternalCaptureState(active);
+            } catch (Exception e) {
+                throw handleException(e);
+            }
+        }
+    }
+
+    // Override toString() in order to have the delegate's ID in it.
+    @Override
+    public String toString() {
+        return mDelegate.toString();
+    }
+
+    /**
+     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
+     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
+     * caller temporarily doesn't have the right permissions to use this service.
+     */
+    void checkPermissions() {
+        enforcePermission(Manifest.permission.RECORD_AUDIO);
+        enforcePermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
+    }
+
+    /**
+     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
+     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
+     * caller temporarily doesn't have the right permissions to preempt active sound trigger
+     * sessions.
+     */
+    void checkPreemptPermissions() {
+        enforcePermission(Manifest.permission.PREEMPT_SOUND_TRIGGER);
+    }
+
+    /**
+     * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
+     * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
+     * caller temporarily doesn't have the given permission.
+     *
+     * @param permission The permission to check.
+     */
+    void enforcePermission(String permission) {
+        final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext,
+                permission);
+        switch (status) {
+            case PermissionChecker.PERMISSION_GRANTED:
+                return;
+            case PermissionChecker.PERMISSION_HARD_DENIED:
+                throw new SecurityException(
+                        String.format("Caller must have the %s permission.", permission));
+            case PermissionChecker.PERMISSION_SOFT_DENIED:
+                throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
+                        String.format("Caller must have the %s permission.", permission));
+            default:
+                throw new InternalServerError(
+                        new RuntimeException("Unexpected perimission check result."));
+        }
+    }
+
+    @Override
+    public IBinder asBinder() {
+        throw new UnsupportedOperationException(
+                "This implementation is not inteded to be used directly with Binder.");
+    }
+
+    @Override public void dump(PrintWriter pw) {
+        synchronized (this) {
+            if (mModules != null) {
+                for (int handle : mModules.keySet()) {
+                    pw.println("=========================================");
+                    pw.printf("Active sessions for module %d", handle);
+                    pw.println();
+                    pw.println("=========================================");
+                    for (ModuleService session : mModules.get(handle)) {
+                        session.dump(pw);
+                    }
+                }
+            }
+        }
+        pw.println();
+
+        if (mDelegate instanceof Dumpable) {
+            ((Dumpable) mDelegate).dump(pw);
+        }
+
+    }
+
+    /** State of a sound model. */
+    static class ModelState {
+        /** Activity state of a sound model. */
+        enum Activity {
+            /** Model is loaded, recognition is inactive. */
+            LOADED,
+            /** Model is loaded, recognition is active. */
+            ACTIVE
+        }
+
+        /** Activity state. */
+        Activity activityState = Activity.LOADED;
+
+        /**
+         * A map of known parameter support. A missing key means we don't know yet whether the
+         * parameter is supported. A null value means it is known to not be supported. A non-null
+         * value indicates the valid value range.
+         */
+        private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();
+
+        /**
+         * Check that the given parameter is known to be supported for this model.
+         *
+         * @param modelParam The parameter key.
+         */
+        void checkSupported(int modelParam) {
+            if (!parameterSupport.containsKey(modelParam)) {
+                throw new IllegalStateException("Parameter has not been checked for support.");
+            }
+            ModelParameterRange range = parameterSupport.get(modelParam);
+            if (range == null) {
+                throw new IllegalArgumentException("Paramater is not supported.");
+            }
+        }
+
+        /**
+         * Check that the given parameter is known to be supported for this model and that the given
+         * value is a valid value for it.
+         *
+         * @param modelParam The parameter key.
+         * @param value      The value.
+         */
+        void checkSupported(int modelParam, int value) {
+            if (!parameterSupport.containsKey(modelParam)) {
+                throw new IllegalStateException("Parameter has not been checked for support.");
+            }
+            ModelParameterRange range = parameterSupport.get(modelParam);
+            if (range == null) {
+                throw new IllegalArgumentException("Paramater is not supported.");
+            }
+            Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive,
+                    "value");
+        }
+
+        /**
+         * Update support state for the given parameter for this model.
+         *
+         * @param modelParam The parameter key.
+         * @param range      The parameter value range, or null if not supported.
+         */
+        void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) {
+            parameterSupport.put(modelParam, range);
+        }
+    }
+
+    /**
+     * A wrapper around an {@link ISoundTriggerModule} implementation, to address the same aspects
+     * mentioned in {@link SoundTriggerModule} above. This class follows the same conventions.
+     */
+    private class ModuleService extends ISoundTriggerModule.Stub implements ISoundTriggerCallback,
+            IBinder.DeathRecipient {
+        private final ISoundTriggerCallback mCallback;
+        private ISoundTriggerModule mDelegate;
+        private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>();
+        private final int mHandle;
+
+        ModuleService(int handle, @NonNull ISoundTriggerCallback callback) {
+            mCallback = callback;
+            mHandle = handle;
+            try {
+                mCallback.asBinder().linkToDeath(null, 0);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+
+        void attach(@NonNull ISoundTriggerModule delegate) {
+            mDelegate = delegate;
+            mModules.get(mHandle).add(this);
+        }
+
+        @Override
+        public int loadModel(@NonNull SoundModel model) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validateGenericModel(model);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    int handle = mDelegate.loadModel(model);
+                    mLoadedModels.put(handle, new ModelState());
+                    return handle;
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public int loadPhraseModel(@NonNull PhraseSoundModel model) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validatePhraseModel(model);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    int handle = mDelegate.loadPhraseModel(model);
+                    mLoadedModels.put(handle, new ModelState());
+                    return handle;
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void unloadModel(int modelHandle) {
+            // Permission check.
+            checkPermissions();
+            // Input validation (always valid).
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                if (modelState.activityState
+                        != ModelState.Activity.LOADED) {
+                    throw new IllegalStateException("Model with handle: " + modelHandle
+                            + " has invalid state for unloading: " + modelState.activityState);
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    mDelegate.unloadModel(modelHandle);
+                    mLoadedModels.remove(modelHandle);
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validateRecognitionConfig(config);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                if (modelState.activityState
+                        != ModelState.Activity.LOADED) {
+                    throw new IllegalStateException("Model with handle: " + modelHandle
+                            + " has invalid state for starting recognition: "
+                            + modelState.activityState);
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    mDelegate.startRecognition(modelHandle, config);
+                    modelState.activityState =
+                            ModelState.Activity.ACTIVE;
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void stopRecognition(int modelHandle) {
+            // Permission check.
+            checkPermissions();
+            // Input validation (always valid).
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                // stopRecognition is idempotent - no need to check model state.
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    mDelegate.stopRecognition(modelHandle);
+                    modelState.activityState =
+                            ModelState.Activity.LOADED;
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void forceRecognitionEvent(int modelHandle) {
+            // Permission check.
+            checkPermissions();
+            // Input validation (always valid).
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                // forceRecognitionEvent is idempotent - no need to check model state.
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    mDelegate.forceRecognitionEvent(modelHandle);
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void setModelParameter(int modelHandle, int modelParam, int value) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validateModelParameter(modelParam);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                modelState.checkSupported(modelParam, value);
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    mDelegate.setModelParameter(modelHandle, modelParam, value);
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public int getModelParameter(int modelHandle, int modelParam) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validateModelParameter(modelParam);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+                modelState.checkSupported(modelParam);
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    return mDelegate.getModelParameter(modelHandle, modelParam);
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        @Nullable
+        public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) {
+            // Permission check.
+            checkPermissions();
+            // Input validation.
+            ValidationUtil.validateModelParameter(modelParam);
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has been detached.");
+                }
+                ModelState modelState = mLoadedModels.get(
+                        modelHandle);
+                if (modelState == null) {
+                    throw new IllegalStateException("Invalid handle: " + modelHandle);
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
+                            modelParam);
+                    modelState.updateParameterSupport(modelParam, result);
+                    return result;
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        @Override
+        public void detach() {
+            // Permission check.
+            checkPermissions();
+            // Input validation (always valid).
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                // State validation.
+                if (mDelegate == null) {
+                    throw new IllegalStateException("Module has already been detached.");
+                }
+                if (!mLoadedModels.isEmpty()) {
+                    throw new IllegalStateException("Cannot detach while models are loaded.");
+                }
+
+                // From here on, every exception isn't client's fault.
+                try {
+                    detachInternal();
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+
+        // Override toString() in order to have the delegate's ID in it.
+        @Override
+        public String toString() {
+            return mDelegate.toString();
+        }
+
+        private void detachInternal() {
+            try {
+                mDelegate.detach();
+                mDelegate = null;
+                mCallback.asBinder().unlinkToDeath(null, 0);
+                mModules.get(mHandle).remove(this);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+
+        void dump(PrintWriter pw) {
+            pw.printf("Loaded models for session %s (handle, active)", toString());
+            pw.println();
+            pw.println("-------------------------------");
+            for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
+                pw.print(entry.getKey());
+                pw.print('\t');
+                pw.print(entry.getValue().activityState.name());
+                pw.println();
+            }
+        }
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Callbacks
+
+        @Override
+        public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) {
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                if (event.status != RecognitionStatus.FORCED) {
+                    mLoadedModels.get(modelHandle).activityState =
+                            ModelState.Activity.LOADED;
+                }
+                try {
+                    mCallback.onRecognition(modelHandle, event);
+                } catch (RemoteException e) {
+                    // Dead client will be handled by binderDied() - no need to handle here.
+                    // In any case, client callbacks are considered best effort.
+                    Log.e(TAG, "Client callback exception.", e);
+                }
+            }
+        }
+
+        @Override
+        public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) {
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                if (event.common.status != RecognitionStatus.FORCED) {
+                    mLoadedModels.get(modelHandle).activityState =
+                            ModelState.Activity.LOADED;
+                }
+                try {
+                    mCallback.onPhraseRecognition(modelHandle, event);
+                } catch (RemoteException e) {
+                    // Dead client will be handled by binderDied() - no need to handle here.
+                    // In any case, client callbacks are considered best effort.
+                    Log.e(TAG, "Client callback exception.", e);
+                }
+            }
+        }
+
+        @Override
+        public void onRecognitionAvailabilityChange(boolean available) {
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                try {
+                    mCallback.onRecognitionAvailabilityChange(available);
+                } catch (RemoteException e) {
+                    // Dead client will be handled by binderDied() - no need to handle here.
+                    // In any case, client callbacks are considered best effort.
+                    Log.e(TAG, "Client callback exception.", e);
+                }
+            }
+        }
+
+        @Override
+        public void onModuleDied() {
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                try {
+                    mCallback.onModuleDied();
+                } catch (RemoteException e) {
+                    // Dead client will be handled by binderDied() - no need to handle here.
+                    // In any case, client callbacks are considered best effort.
+                    Log.e(TAG, "Client callback exception.", e);
+                }
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            // This is called whenever our client process dies.
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                try {
+                    // Gracefully stop all active recognitions and unload the models.
+                    for (Map.Entry<Integer, ModelState> entry :
+                            mLoadedModels.entrySet()) {
+                        if (entry.getValue().activityState
+                                == ModelState.Activity.ACTIVE) {
+                            mDelegate.stopRecognition(entry.getKey());
+                        }
+                        mDelegate.unloadModel(entry.getKey());
+                    }
+                    // Detach.
+                    detachInternal();
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index aa1558e..d6390184 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -123,7 +123,6 @@
      */
     synchronized @NonNull
     ISoundTriggerModule attach(@NonNull ISoundTriggerCallback callback) {
-        Log.d(TAG, "attach()");
         Session session = new Session(callback);
         mActiveSessions.add(session);
         return session;
@@ -149,8 +148,6 @@
      * @param active true iff external capture is active.
      */
     synchronized void setExternalCaptureState(boolean active) {
-        Log.d(TAG, String.format("setExternalCaptureState(active=%b)", active));
-
         if (mProperties.concurrentCapture) {
             // If we support concurrent capture, we don't care about any of this.
             return;
@@ -235,7 +232,6 @@
 
         @Override
         public void detach() {
-            Log.d(TAG, "detach()");
             synchronized (SoundTriggerModule.this) {
                 if (mCallback == null) {
                     return;
@@ -247,8 +243,6 @@
 
         @Override
         public int loadModel(@NonNull SoundModel model) {
-            Log.d(TAG, String.format("loadModel(model=%s)", model));
-
             // We must do this outside the lock, to avoid possible deadlocks with the remote process
             // that provides the audio sessions, which may also be calling into us.
             SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
@@ -276,8 +270,6 @@
 
         @Override
         public int loadPhraseModel(@NonNull PhraseSoundModel model) {
-            Log.d(TAG, String.format("loadPhraseModel(model=%s)", model));
-
             // We must do this outside the lock, to avoid possible deadlocks with the remote process
             // that provides the audio sessions, which may also be calling into us.
             SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
@@ -306,10 +298,7 @@
 
         @Override
         public void unloadModel(int modelHandle) {
-            Log.d(TAG, String.format("unloadModel(handle=%d)", modelHandle));
-
             int sessionId;
-
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 sessionId = mLoadedModels.get(modelHandle).unload();
@@ -323,8 +312,6 @@
 
         @Override
         public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) {
-            Log.d(TAG,
-                    String.format("startRecognition(handle=%d, config=%s)", modelHandle, config));
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 mLoadedModels.get(modelHandle).startRecognition(config);
@@ -333,7 +320,6 @@
 
         @Override
         public void stopRecognition(int modelHandle) {
-            Log.d(TAG, String.format("stopRecognition(handle=%d)", modelHandle));
             synchronized (SoundTriggerModule.this) {
                 mLoadedModels.get(modelHandle).stopRecognition();
             }
@@ -341,7 +327,6 @@
 
         @Override
         public void forceRecognitionEvent(int modelHandle) {
-            Log.d(TAG, String.format("forceRecognitionEvent(handle=%d)", modelHandle));
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 mLoadedModels.get(modelHandle).forceRecognitionEvent();
@@ -350,9 +335,6 @@
 
         @Override
         public void setModelParameter(int modelHandle, int modelParam, int value) {
-            Log.d(TAG,
-                    String.format("setModelParameter(handle=%d, param=%d, value=%d)", modelHandle,
-                            modelParam, value));
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 mLoadedModels.get(modelHandle).setParameter(modelParam, value);
@@ -361,8 +343,6 @@
 
         @Override
         public int getModelParameter(int modelHandle, int modelParam) {
-            Log.d(TAG, String.format("getModelParameter(handle=%d, param=%d)", modelHandle,
-                    modelParam));
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 return mLoadedModels.get(modelHandle).getParameter(modelParam);
@@ -372,8 +352,6 @@
         @Override
         @Nullable
         public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) {
-            Log.d(TAG, String.format("queryModelParameterSupport(handle=%d, param=%d)", modelHandle,
-                    modelParam));
             synchronized (SoundTriggerModule.this) {
                 checkValid();
                 return mLoadedModels.get(modelHandle).queryModelParameterSupport(modelParam);
@@ -584,8 +562,6 @@
             public void recognitionCallback(
                     @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent,
                     int cookie) {
-                Log.d(TAG, String.format("recognitionCallback_2_1(event=%s, cookie=%d)",
-                        recognitionEvent, cookie));
                 synchronized (SoundTriggerModule.this) {
                     android.media.soundtrigger_middleware.RecognitionEvent aidlEvent =
                             ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent);
@@ -608,8 +584,6 @@
             public void phraseRecognitionCallback(
                     @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent,
                     int cookie) {
-                Log.d(TAG, String.format("phraseRecognitionCallback_2_1(event=%s, cookie=%d)",
-                        phraseRecognitionEvent, cookie));
                 synchronized (SoundTriggerModule.this) {
                     android.media.soundtrigger_middleware.PhraseRecognitionEvent aidlEvent =
                             ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 2115f7c..6eb3c0f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1173,6 +1173,10 @@
             }
         };
 
+        private Runnable mTryToRebindRunnable = () -> {
+            tryToRebind();
+        };
+
         WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) {
             mInfo = info;
             mWallpaper = wallpaper;
@@ -1279,7 +1283,7 @@
                         saveSettingsLocked(mWallpaper.userId);
                     }
                     FgThread.getHandler().removeCallbacks(mResetRunnable);
-                    mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind);
+                    mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable);
                 }
             }
         }
@@ -1337,7 +1341,7 @@
                         < WALLPAPER_RECONNECT_TIMEOUT_MS) {
                     // Bind fail without timeout, schedule rebind
                     Slog.w(TAG, "Rebind fail! Try again later");
-                    mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000);
+                    mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000);
                 } else {
                     // Timeout
                     Slog.w(TAG, "Reverting to built-in wallpaper!");
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e5b8403..76bc366 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4178,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);
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/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f52c7f2..3210304 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1819,12 +1819,12 @@
      */
     private int deliverToCurrentTopIfNeeded(ActivityStack topStack) {
         final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
-        final boolean dontStart = top != null
+        final boolean dontStart = top != null && mStartActivity.resultTo == null
                 && top.mActivityComponent.equals(mStartActivity.mActivityComponent)
                 && top.mUserId == mStartActivity.mUserId
                 && top.attachedToProcess()
                 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
-                    || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
+                || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK))
                 // This allows home activity to automatically launch on secondary display when
                 // display added, if home was the top activity on default display, instead of
                 // sending new intent to the home activity on default display.
@@ -2055,6 +2055,8 @@
                 && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
 
+        sendNewTaskResultRequestIfNeeded();
+
         if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
             mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
         }
@@ -2236,8 +2238,6 @@
                 mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
             }
         }
-
-        sendNewTaskResultRequestIfNeeded();
     }
 
     private void computeSourceStack() {
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 d2d7ad3..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);
@@ -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 ca09537..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();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 30e8da2..5cd2930 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,7 +94,6 @@
 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;
@@ -131,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;
@@ -1005,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)
@@ -2232,12 +2231,6 @@
      * for bounds calculations.
      */
     void preOnConfigurationChanged() {
-        final DockedStackDividerController dividerController = getDockedDividerController();
-
-        if (dividerController != null) {
-            getDockedDividerController().onConfigurationChanged();
-        }
-
         final PinnedStackController pinnedStackController = getPinnedStackController();
 
         if (pinnedStackController != null) {
@@ -2621,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);
@@ -2633,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);
         }
 
@@ -2746,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()
@@ -2892,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);
@@ -3062,8 +3005,6 @@
         }
 
         pw.println();
-        mDividerControllerLocked.dump(prefix, pw);
-        pw.println();
         mPinnedStackControllerLocked.dump(prefix, pw);
 
         pw.println();
@@ -4084,7 +4025,7 @@
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
 
-        mWmService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
+        mWmService.mH.sendEmptyMessage(UPDATE_MULTI_WINDOW_STACKS);
     }
 
     /**
@@ -4692,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;
@@ -6167,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 9468bff..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 {
@@ -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/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/Task.java b/services/core/java/com/android/server/wm/Task.java
index 07e17e8..27acb23 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2108,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 */);
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/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 240f566..4ac809d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -527,9 +527,9 @@
     /**
      * Hide IME using imeTargetWindow when requested.
      *
-     * @param displayId on which IME is shown
+     * @param imeTargetWindowToken token of the (IME target) window on which IME should be hidden.
      */
-    public abstract void hideIme(int displayId);
+    public abstract void hideIme(IBinder imeTargetWindowToken);
 
     /**
      * Tell window manager about a package that should not be running with high refresh rate
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e0f8f0e..0169a4f 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()")) {
@@ -7490,27 +7441,28 @@
                     return;
                 }
                 imeTarget = imeTarget.getImeControlTarget();
-
-                final int displayId = imeTarget.getDisplayId();
-                mRoot.getDisplayContent(displayId).getInsetsStateController().getImeSourceProvider()
+                imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider()
                         .scheduleShowImePostLayout(imeTarget);
             }
         }
 
         @Override
-        public void hideIme(int displayId) {
+        public void hideIme(IBinder imeTargetWindowToken) {
             synchronized (mGlobalLock) {
-                final DisplayContent dc = mRoot.getDisplayContent(displayId);
-                if (dc != null) {
-                    InsetsControlTarget imeControlTarget = dc.mInputMethodControlTarget;
-                    if (imeControlTarget == null) {
-                        return;
-                    }
-                    // If there was a pending IME show(), reset it as IME has been
-                    // requested to be hidden.
-                    dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
-                    imeControlTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
+                WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
+                if (imeTarget == null) {
+                    // The target window no longer exists.
+                    return;
                 }
+                final DisplayContent dc = imeTarget.getImeControlTarget().getDisplayContent();
+                // If there was a pending IME show(), reset it as IME has been
+                // requested to be hidden.
+                dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
+                if (dc.mInputMethodControlTarget == null) {
+                    return;
+                }
+                dc.mInputMethodControlTarget.hideInsets(
+                        WindowInsets.Type.ime(), true /* fromIme */);
             }
         }
 
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/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 5a8e25e4..05aa359 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -355,10 +355,11 @@
 }
 
 static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
-                                   jobject vibration) {
+                                   jobject vibration, jboolean withCallback) {
     if (auto hal = getHal<aidl::IVibrator>()) {
         int32_t lengthMs;
-        sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
+        sp<AidlVibratorCallback> effectCallback =
+                (withCallback != JNI_FALSE ? new AidlVibratorCallback(env, vibration) : nullptr);
         aidl::Effect effectType(static_cast<aidl::Effect>(effect));
         aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
 
@@ -478,24 +479,24 @@
 }
 
 static const JNINativeMethod method_table[] = {
-    { "vibratorExists", "()Z", (void*)vibratorExists },
-    { "vibratorInit", "()V", (void*)vibratorInit },
-    { "vibratorOn", "(J)V", (void*)vibratorOn },
-    { "vibratorOff", "()V", (void*)vibratorOff },
-    { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
-    { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
-    { "vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;)J",
-            (void*)vibratorPerformEffect},
-    { "vibratorPerformComposedEffect",
-            "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/VibratorService$Vibration;)V",
-            (void*)vibratorPerformComposedEffect},
-    { "vibratorGetSupportedEffects", "()[I",
-            (void*)vibratorGetSupportedEffects},
-    { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
-    { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
-    { "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
-    { "vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
-    { "vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
+        {"vibratorExists", "()Z", (void*)vibratorExists},
+        {"vibratorInit", "()V", (void*)vibratorInit},
+        {"vibratorOn", "(J)V", (void*)vibratorOn},
+        {"vibratorOff", "()V", (void*)vibratorOff},
+        {"vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
+        {"vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
+        {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J",
+         (void*)vibratorPerformEffect},
+        {"vibratorPerformComposedEffect",
+         "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
+         "VibratorService$Vibration;)V",
+         (void*)vibratorPerformComposedEffect},
+        {"vibratorGetSupportedEffects", "()[I", (void*)vibratorGetSupportedEffects},
+        {"vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
+        {"vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
+        {"vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
+        {"vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
+        {"vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
 };
 
 int register_android_server_VibratorService(JNIEnv *env) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ff8c209..c1ac55f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -394,6 +394,7 @@
         mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
         mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
         mRuntimeStartUptime = SystemClock.uptimeMillis();
+        Process.setStartTimes(mRuntimeStartElapsedTime, mRuntimeStartUptime);
 
         // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
         // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 5d7f4e9..983a639 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -17,6 +17,7 @@
 package com.android.server.people;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionSessionId;
@@ -145,14 +146,15 @@
             mDataManager.pruneDataForUser(userId, signal);
         }
 
+        @Nullable
         @Override
-        public byte[] backupConversationInfos(@UserIdInt int userId) {
-            return new byte[0];
+        public byte[] getBackupPayload(@UserIdInt int userId) {
+            return mDataManager.getBackupPayload(userId);
         }
 
         @Override
-        public void restoreConversationInfos(@UserIdInt int userId, @NonNull String key,
-                @NonNull byte[] payload) {
+        public void restore(@UserIdInt int userId, @NonNull byte[] payload) {
+            mDataManager.restore(userId, payload);
         }
 
         @VisibleForTesting
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 41bc361..dc3fa2a 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -24,6 +24,7 @@
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutInfo.ShortcutFlags;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
@@ -31,6 +32,10 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.people.ConversationInfoProto;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -280,6 +285,25 @@
         }
     }
 
+    @Nullable
+    byte[] getBackupPayload() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        try {
+            out.writeUTF(mShortcutId);
+            out.writeUTF(mLocusId != null ? mLocusId.getId() : "");
+            out.writeUTF(mContactUri != null ? mContactUri.toString() : "");
+            out.writeUTF(mNotificationChannelId != null ? mNotificationChannelId : "");
+            out.writeInt(mShortcutFlags);
+            out.writeInt(mConversationFlags);
+            out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : "");
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write fields to backup payload.", e);
+            return null;
+        }
+        return baos.toByteArray();
+    }
+
     /** Reads from {@link ProtoInputStream} and constructs a {@link ConversationInfo}. */
     @NonNull
     static ConversationInfo readFromProto(@NonNull ProtoInputStream protoInputStream)
@@ -331,6 +355,37 @@
         return builder.build();
     }
 
+    @Nullable
+    static ConversationInfo readFromBackupPayload(@NonNull byte[] payload) {
+        ConversationInfo.Builder builder = new ConversationInfo.Builder();
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
+        try {
+            builder.setShortcutId(in.readUTF());
+            String locusId = in.readUTF();
+            if (!TextUtils.isEmpty(locusId)) {
+                builder.setLocusId(new LocusId(locusId));
+            }
+            String contactUri = in.readUTF();
+            if (!TextUtils.isEmpty(contactUri)) {
+                builder.setContactUri(Uri.parse(contactUri));
+            }
+            String notificationChannelId = in.readUTF();
+            if (!TextUtils.isEmpty(notificationChannelId)) {
+                builder.setNotificationChannelId(notificationChannelId);
+            }
+            builder.setShortcutFlags(in.readInt());
+            builder.setConversationFlags(in.readInt());
+            String contactPhoneNumber = in.readUTF();
+            if (!TextUtils.isEmpty(contactPhoneNumber)) {
+                builder.setContactPhoneNumber(contactPhoneNumber);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read conversation info fields from backup payload.", e);
+            return null;
+        }
+        return builder.build();
+    }
+
     /**
      * Builder class for {@link ConversationInfo} objects.
      */
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 89c4972..2f2a95c 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -31,6 +31,10 @@
 
 import com.google.android.collect.Lists;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -48,6 +52,8 @@
 
     private static final String CONVERSATIONS_FILE_NAME = "conversations";
 
+    private static final int CONVERSATION_INFOS_END_TOKEN = -1;
+
     // Shortcut ID -> Conversation Info
     @GuardedBy("this")
     private final Map<String, ConversationInfo> mConversationInfoMap = new ArrayMap<>();
@@ -195,6 +201,51 @@
         mConversationInfosProtoDiskReadWriter.deleteConversationsFile();
     }
 
+    @Nullable
+    synchronized byte[] getBackupPayload() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream conversationInfosOut = new DataOutputStream(baos);
+        for (ConversationInfo conversationInfo : mConversationInfoMap.values()) {
+            byte[] backupPayload = conversationInfo.getBackupPayload();
+            if (backupPayload == null) {
+                continue;
+            }
+            try {
+                conversationInfosOut.writeInt(backupPayload.length);
+                conversationInfosOut.write(backupPayload);
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to write conversation info to backup payload.", e);
+                return null;
+            }
+        }
+        try {
+            conversationInfosOut.writeInt(CONVERSATION_INFOS_END_TOKEN);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write conversation infos end token to backup payload.", e);
+            return null;
+        }
+        return baos.toByteArray();
+    }
+
+    synchronized void restore(@NonNull byte[] payload) {
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
+        try {
+            for (int conversationInfoSize = in.readInt();
+                    conversationInfoSize != CONVERSATION_INFOS_END_TOKEN;
+                    conversationInfoSize = in.readInt()) {
+                byte[] conversationInfoPayload = new byte[conversationInfoSize];
+                in.readFully(conversationInfoPayload, 0, conversationInfoSize);
+                ConversationInfo conversationInfo = ConversationInfo.readFromBackupPayload(
+                        conversationInfoPayload);
+                if (conversationInfo != null) {
+                    addOrUpdate(conversationInfo);
+                }
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read conversation info from payload.", e);
+        }
+    }
+
     @MainThread
     private synchronized void updateConversationsInMemory(
             @NonNull ConversationInfo conversationInfo) {
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 3a34c6a..e4ce6ba 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -334,6 +334,25 @@
         });
     }
 
+    /** Retrieves a backup payload blob for specified user id. */
+    @Nullable
+    public byte[] getBackupPayload(@UserIdInt int userId) {
+        UserData userData = getUnlockedUserData(userId);
+        if (userData == null) {
+            return null;
+        }
+        return userData.getBackupPayload();
+    }
+
+    /** Attempts to restore data for the specified user id. */
+    public void restore(@UserIdInt int userId, @NonNull byte[] payload) {
+        UserData userData = getUnlockedUserData(userId);
+        if (userData == null) {
+            return;
+        }
+        userData.restore(payload);
+    }
+
     private int mimeTypeToShareEventType(String mimeType) {
         if (mimeType.startsWith("text/")) {
             return Event.TYPE_SHARE_TEXT;
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index 0f8b91b..ed8c595 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -22,8 +22,14 @@
 import android.os.Environment;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.Slog;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.Consumer;
@@ -31,6 +37,10 @@
 /** The data associated with a user profile. */
 class UserData {
 
+    private static final String TAG = UserData.class.getSimpleName();
+
+    private static final int CONVERSATIONS_END_TOKEN = -1;
+
     private final @UserIdInt int mUserId;
 
     private final File mPerUserPeopleDataDir;
@@ -125,6 +135,48 @@
         return mDefaultSmsApp != null ? getPackageData(mDefaultSmsApp) : null;
     }
 
+    @Nullable
+    byte[] getBackupPayload() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        for (PackageData packageData : mPackageDataMap.values()) {
+            try {
+                byte[] conversationsBackupPayload =
+                        packageData.getConversationStore().getBackupPayload();
+                out.writeInt(conversationsBackupPayload.length);
+                out.write(conversationsBackupPayload);
+                out.writeUTF(packageData.getPackageName());
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to write conversations to backup payload.", e);
+                return null;
+            }
+        }
+        try {
+            out.writeInt(CONVERSATIONS_END_TOKEN);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write conversations end token to backup payload.", e);
+            return null;
+        }
+        return baos.toByteArray();
+    }
+
+    void restore(@NonNull byte[] payload) {
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
+        try {
+            for (int conversationsPayloadSize = in.readInt();
+                    conversationsPayloadSize != CONVERSATIONS_END_TOKEN;
+                    conversationsPayloadSize = in.readInt()) {
+                byte[] conversationsPayload = new byte[conversationsPayloadSize];
+                in.readFully(conversationsPayload, 0, conversationsPayloadSize);
+                String packageName = in.readUTF();
+                getOrCreatePackageData(packageName).getConversationStore().restore(
+                        conversationsPayload);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to restore conversations from backup payload.", e);
+        }
+    }
+
     private PackageData createPackageData(String packageName) {
         return new PackageData(packageName, mUserId, this::isDefaultDialer, this::isDefaultSmsApp,
                 mScheduledExecutorService, mPerUserPeopleDataDir);
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 407f67e..44f4ccf 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
 
+import android.app.compat.ChangeIdStateCache;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -74,6 +75,7 @@
         // Assume userdebug/eng non-final build
         when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
         when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+        ChangeIdStateCache.disable();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 4a686ee..53b90f2 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -62,6 +62,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        android.app.compat.ChangeIdStateCache.disable();
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
                 new PackageManager.NameNotFoundException());
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index be873bd..d9101bf 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -60,6 +60,7 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
+import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -119,7 +120,6 @@
     private static final String PLAY_STORE_PKG = "com.android.vending";
     private static final String ADB_INSTALLER = "adb";
     private static final String PLAY_STORE_CERT = "play_store_cert";
-    private static final String ADB_CERT = "";
 
     @org.junit.Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -137,11 +137,12 @@
     @Mock
     Handler mHandler;
 
+    private final Context mRealContext = InstrumentationRegistry.getTargetContext();
+
     private PackageManager mSpyPackageManager;
     private File mTestApk;
     private File mTestApkTwoCerts;
 
-    private final Context mRealContext = InstrumentationRegistry.getTargetContext();
     // under test
     private AppIntegrityManagerServiceImpl mService;
 
@@ -163,8 +164,7 @@
                         mPackageManagerInternal,
                         mRuleEvaluationEngine,
                         mIntegrityFileManager,
-                        mHandler,
-                        /* checkIntegrityForRuleProviders= */ true);
+                        mHandler);
 
         mSpyPackageManager = spy(mRealContext.getPackageManager());
         // setup mocks to prevent NPE
@@ -172,6 +172,9 @@
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockResources.getStringArray(anyInt())).thenReturn(new String[]{});
         when(mIntegrityFileManager.initialized()).thenReturn(true);
+        // These are needed to override the Settings.Global.get result.
+        when(mMockContext.getContentResolver()).thenReturn(mRealContext.getContentResolver());
+        setIntegrityCheckIncludesRuleProvider(true);
     }
 
     @After
@@ -201,6 +204,7 @@
     @Test
     public void updateRuleSet_notSystemApp() throws Exception {
         whitelistUsAsRuleProvider();
+        makeUsSystemApp(false);
         Rule rule =
                 new Rule(
                         new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
@@ -411,14 +415,7 @@
     public void verifierAsInstaller_skipIntegrityVerification() throws Exception {
         whitelistUsAsRuleProvider();
         makeUsSystemApp();
-        mService =
-                new AppIntegrityManagerServiceImpl(
-                        mMockContext,
-                        mPackageManagerInternal,
-                        mRuleEvaluationEngine,
-                        mIntegrityFileManager,
-                        mHandler,
-                        /* checkIntegrityForRuleProviders= */ false);
+        setIntegrityCheckIncludesRuleProvider(false);
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         verify(mMockContext, atLeastOnce())
@@ -460,12 +457,21 @@
     }
 
     private void makeUsSystemApp() throws Exception {
+        makeUsSystemApp(true);
+    }
+
+    private void makeUsSystemApp(boolean isSystemApp) throws Exception {
         PackageInfo packageInfo =
                 mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, 0);
-        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        if (isSystemApp) {
+            packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        } else {
+            packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
+        }
         doReturn(packageInfo)
                 .when(mSpyPackageManager)
                 .getPackageInfo(eq(TEST_FRAMEWORK_PACKAGE), anyInt());
+        when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
     }
 
     private Intent makeVerificationIntent() throws Exception {
@@ -492,4 +498,13 @@
         intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE);
         return intent;
     }
+
+    private void setIntegrityCheckIncludesRuleProvider(boolean shouldInclude) throws Exception {
+        int value = shouldInclude ? 1 : 0;
+        Settings.Global.putInt(mRealContext.getContentResolver(),
+                Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, value);
+        assertThat(Settings.Global.getInt(mRealContext.getContentResolver(),
+                Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, -1) == 1).isEqualTo(
+                shouldInclude);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index 233e16c..e08eea2 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -24,6 +24,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.ExpectedException
+import java.lang.UnsupportedOperationException
 
 class OverlayActorEnforcerTests {
     companion object {
@@ -159,7 +160,7 @@
         private val hasPermission: Boolean = false,
         private val overlayableInfo: OverlayableInfo? = null,
         private vararg val packageNames: String = arrayOf("com.test.actor.one")
-    ) : OverlayActorEnforcer.VerifyCallback {
+    ) : OverlayableInfoCallback {
 
         override fun getNamedActors() = if (isActor) {
             mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
@@ -169,7 +170,7 @@
 
         override fun getOverlayableForTarget(
             packageName: String,
-            targetOverlayableName: String?,
+            targetOverlayableName: String,
             userId: Int
         ) = overlayableInfo
 
@@ -193,5 +194,9 @@
                 throw SecurityException()
             }
         }
+
+        override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean {
+            throw UnsupportedOperationException()
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index a428a97..cd73432 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -24,30 +24,16 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
-import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.util.ArraySet;
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.content.om.OverlayConfig;
-
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
 public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index a753aac..820e61c 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -23,10 +23,13 @@
 import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
 import android.content.om.OverlayInfo.State;
+import android.content.om.OverlayableInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.util.ArraySet;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.content.om.OverlayConfig;
 
 import org.junit.Before;
@@ -35,6 +38,7 @@
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -281,8 +285,8 @@
         }
     }
 
-    static final class DummyPackageManagerHelper implements
-            OverlayManagerServiceImpl.PackageManagerHelper {
+    static final class DummyPackageManagerHelper implements PackageManagerHelper,
+            OverlayableInfoCallback {
         private final DummyDeviceState mState;
 
         private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -320,6 +324,35 @@
                     .map(p -> getPackageInfo(p.packageName, p.userId))
                     .collect(Collectors.toList());
         }
+
+        @Nullable
+        @Override
+        public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+                @NonNull String targetOverlayableName, int userId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Nullable
+        @Override
+        public String[] getPackagesForUid(int uid) {
+            throw new UnsupportedOperationException();
+        }
+
+        @NonNull
+        @Override
+        public Map<String, Map<String, String>> getNamedActors() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void enforcePermission(String permission, String message) throws SecurityException {
+            throw new UnsupportedOperationException();
+        }
     }
 
     static class DummyIdmapManager extends IdmapManager {
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index d138700..4e63237 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -284,6 +284,30 @@
         assertEquals(in2, out2);
     }
 
+    @Test
+    public void testBackupAndRestore() {
+        ConversationInfo in1 = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI,
+                PHONE_NUMBER, NOTIFICATION_CHANNEL_ID);
+        ConversationInfo in2 = buildConversationInfo(SHORTCUT_ID_2, LOCUS_ID_2, CONTACT_URI_2,
+                PHONE_NUMBER_2, NOTIFICATION_CHANNEL_ID_2);
+        mConversationStore.addOrUpdate(in1);
+        mConversationStore.addOrUpdate(in2);
+
+        byte[] backupPayload = mConversationStore.getBackupPayload();
+        assertNotNull(backupPayload);
+
+        ConversationStore conversationStore = new ConversationStore(mFile,
+                mMockScheduledExecutorService);
+        ConversationInfo out1 = conversationStore.getConversation(SHORTCUT_ID);
+        assertNull(out1);
+
+        conversationStore.restore(backupPayload);
+        out1 = conversationStore.getConversation(SHORTCUT_ID);
+        ConversationInfo out2 = conversationStore.getConversation(SHORTCUT_ID_2);
+        assertEquals(in1, out1);
+        assertEquals(in2, out2);
+    }
+
     private void resetConversationStore() {
         mFile.mkdir();
         mMockScheduledExecutorService = new MockScheduledExecutorService();
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index f0b7d20..e57df24 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -653,6 +653,33 @@
         assertTrue(activeTimeSlots.isEmpty());
     }
 
+    @Test
+    public void testBackupAndRestoration()
+            throws IntentFilter.MalformedMimeTypeException {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                null);
+        AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
+                .build();
+        AppTargetEvent appTargetEvent =
+                new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+                        .setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE)
+                        .build();
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
+
+        mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
+        byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY);
+
+        DataManager dataManager = new DataManager(mContext, mInjector);
+        dataManager.onUserUnlocked(USER_ID_PRIMARY);
+        dataManager.restore(USER_ID_PRIMARY, payload);
+        ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
+                .getConversationStore()
+                .getConversation(TEST_SHORTCUT_ID);
+        assertNotNull(conversationInfo);
+        assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
+    }
+
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
         LocalServices.removeServiceForTest(clazz);
         LocalServices.addService(clazz, mock);
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 29b0df5..b6cdbfb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1163,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
@@ -1185,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
@@ -1247,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
@@ -3452,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);
@@ -3469,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
@@ -4343,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[]
@@ -4352,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[]{},
@@ -4363,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
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/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 71d3194..0ef2582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -250,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());
 
@@ -307,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
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/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 3c0e0af..0b24dd2 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -60,7 +60,6 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
-import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionService;
@@ -684,9 +683,9 @@
         }
 
         @Override
-        public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
+        public void showSession(Bundle args, int flags) {
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
 
                 final long caller = Binder.clearCallingIdentity();
                 try {
@@ -928,12 +927,10 @@
         }
 
         //----------------- Model management APIs --------------------------------//
-        // TODO: add check to only allow active voice interaction service or keyphrase enrollment
-        //       application to manage voice models
 
         @Override
         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
-            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+            enforceCallerAllowedToEnrollVoiceModel();
 
             if (bcp47Locale == null) {
                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
@@ -950,7 +947,7 @@
 
         @Override
         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
-            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+            enforceCallerAllowedToEnrollVoiceModel();
             if (model == null) {
                 throw new IllegalArgumentException("Model must not be null");
             }
@@ -975,7 +972,7 @@
 
         @Override
         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
-            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+            enforceCallerAllowedToEnrollVoiceModel();
 
             if (bcp47Locale == null) {
                 throw new IllegalArgumentException(
@@ -1008,10 +1005,9 @@
 
         //----------------- SoundTrigger APIs --------------------------------//
         @Override
-        public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
-                String bcp47Locale) {
+        public boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale) {
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             if (bcp47Locale == null) {
@@ -1030,10 +1026,10 @@
         }
 
         @Nullable
-        public KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service,
-                String keyphrase, String bcp47Locale) {
+        public KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase,
+                String bcp47Locale) {
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             if (bcp47Locale == null) {
@@ -1065,10 +1061,10 @@
         }
 
         @Override
-        public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
+        public ModuleProperties getDspModuleProperties() {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
 
                 final long caller = Binder.clearCallingIdentity();
                 try {
@@ -1080,12 +1076,11 @@
         }
 
         @Override
-        public int startRecognition(IVoiceInteractionService service, int keyphraseId,
-                String bcp47Locale, IRecognitionStatusCallback callback,
-                RecognitionConfig recognitionConfig) {
+        public int startRecognition(int keyphraseId, String bcp47Locale,
+                IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
 
                 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
                     throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
@@ -1117,11 +1112,10 @@
         }
 
         @Override
-        public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
-                IRecognitionStatusCallback callback) {
+        public int stopRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             final long caller = Binder.clearCallingIdentity();
@@ -1133,11 +1127,10 @@
         }
 
         @Override
-        public int setParameter(IVoiceInteractionService service, int keyphraseId,
-                @ModelParams int modelParam, int value) {
+        public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             final long caller = Binder.clearCallingIdentity();
@@ -1149,11 +1142,10 @@
         }
 
         @Override
-        public int getParameter(IVoiceInteractionService service, int keyphraseId,
-                @ModelParams int modelParam) {
+        public int getParameter(int keyphraseId, @ModelParams int modelParam) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             final long caller = Binder.clearCallingIdentity();
@@ -1166,11 +1158,10 @@
 
         @Override
         @Nullable
-        public ModelParamRange queryParameter(IVoiceInteractionService service,
-                int keyphraseId, @ModelParams int modelParam) {
+        public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) {
             // Allow the call if this is the current voice interaction service.
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
             }
 
             final long caller = Binder.clearCallingIdentity();
@@ -1400,9 +1391,9 @@
         }
 
         @Override
-        public void setUiHints(IVoiceInteractionService service, Bundle hints) {
+        public void setUiHints(Bundle hints) {
             synchronized (this) {
-                enforceIsCurrentVoiceInteractionService(service);
+                enforceIsCurrentVoiceInteractionService();
 
                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
                 for (int i = 0; i < size; ++i) {
@@ -1425,14 +1416,32 @@
             }
         }
 
-        private void enforceIsCurrentVoiceInteractionService(IVoiceInteractionService service) {
-            if (mImpl == null || mImpl.mService == null
-                    || service.asBinder() != mImpl.mService.asBinder()) {
+        private void enforceIsCurrentVoiceInteractionService() {
+            if (!isCallerCurrentVoiceInteractionService()) {
                 throw new
                     SecurityException("Caller is not the current voice interaction service");
             }
         }
 
+        private void enforceCallerAllowedToEnrollVoiceModel() {
+            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+            if (!isCallerCurrentVoiceInteractionService()
+                    && !isCallerTrustedEnrollmentApplication()) {
+                throw new SecurityException("Caller is required to be the current voice interaction"
+                        + " service or a system enrollment application to enroll voice models");
+            }
+        }
+
+        private boolean isCallerCurrentVoiceInteractionService() {
+            return mImpl != null
+                    && mImpl.mInfo.getServiceInfo().applicationInfo.uid == Binder.getCallingUid();
+        }
+
+        private boolean isCallerTrustedEnrollmentApplication() {
+            return mImpl.mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication(
+                    Binder.getCallingUid());
+        }
+
         private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
             mImpl = impl;
             mAtmInternal.notifyActiveVoiceInteractionServiceChanged(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index a62b03c..b813f87 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -36,6 +36,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -78,6 +79,7 @@
     final IActivityManager mAm;
     final IActivityTaskManager mAtm;
     final VoiceInteractionServiceInfo mInfo;
+    final KeyphraseEnrollmentInfo mEnrollmentApplicationInfo;
     final ComponentName mSessionComponentName;
     final IWindowManager mIWindowManager;
     boolean mBound = false;
@@ -133,6 +135,7 @@
         mComponent = service;
         mAm = ActivityManager.getService();
         mAtm = ActivityTaskManager.getService();
+        mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(context.getPackageManager());
         VoiceInteractionServiceInfo info;
         try {
             info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
@@ -403,6 +406,7 @@
             pw.println("  Active session:");
             mActiveSession.dump("    ", pw);
         }
+        pw.println("  " + mEnrollmentApplicationInfo.toString());
     }
 
     void startLocked() {
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/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a36df49..31d9654 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -11071,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 {
@@ -11174,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/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 6f44230..c1d05e4 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -59,6 +59,7 @@
         "libprotobuf-cpp-full",
         "libz",
         "libbuildversion",
+        "libidmap2_policies",
     ],
     stl: "libc++_static",
     group_static_libs: true,
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 137fbd6..1eb7d95 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -32,10 +32,16 @@
 #include "text/Printer.h"
 #include "util/Util.h"
 
+#include "idmap2/Policies.h"
+
 using ::aapt::text::Printer;
 using ::android::StringPiece;
 using ::android::base::StringPrintf;
 
+using android::idmap2::policy::kPolicyStringToFlag;
+
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 namespace {
@@ -246,32 +252,25 @@
   Printer* printer_;
 };
 
-std::string OverlayablePoliciesToString(OverlayableItem::PolicyFlags policies) {
-  static const std::map<OverlayableItem::PolicyFlags, std::string> kFlagToString = {
-    {OverlayableItem::kPublic, "public"},
-    {OverlayableItem::kSystem, "system"},
-    {OverlayableItem::kVendor, "vendor"},
-    {OverlayableItem::kProduct, "product"},
-    {OverlayableItem::kSignature, "signature"},
-    {OverlayableItem::kOdm, "odm"},
-    {OverlayableItem::kOem, "oem"},
-  };
+std::string OverlayablePoliciesToString(PolicyFlags policies) {
   std::string str;
-  for (auto const& policy : kFlagToString) {
-    if ((policies & policy.first) != policy.first) {
+
+  uint32_t remaining = policies;
+  for (auto const& policy : kPolicyStringToFlag) {
+    if ((policies & policy.second) != policy.second) {
       continue;
     }
     if (!str.empty()) {
       str.append("|");
     }
-    str.append(policy.second);
-    policies &= ~policy.first;
+    str.append(policy.first.data());
+    remaining &= ~policy.second;
   }
-  if (policies != 0) {
+  if (remaining != 0) {
     if (!str.empty()) {
       str.append("|");
     }
-    str.append(StringPrintf("0x%08x", policies));
+    str.append(StringPrintf("0x%08x", remaining));
   }
   return !str.empty() ? str : "none";
 }
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 74e2a098..234cbc4 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -32,11 +32,15 @@
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 
+#include "idmap2/Policies.h"
+
 using ::aapt::ResourceUtils::StringBuilder;
 using ::aapt::text::Utf8Iterator;
 using ::android::ConfigDescription;
 using ::android::StringPiece;
 
+using android::idmap2::policy::kPolicyStringToFlag;
+
 namespace aapt {
 
 constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
@@ -1063,7 +1067,7 @@
 
   bool error = false;
   std::string comment;
-  OverlayableItem::PolicyFlags current_policies = OverlayableItem::Policy::kNone;
+  PolicyFlags current_policies = PolicyFlags::NONE;
   const size_t start_depth = parser->depth();
   while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
     xml::XmlPullParser::Event event = parser->event();
@@ -1073,7 +1077,7 @@
     } else if (event == xml::XmlPullParser::Event::kEndElement
                && parser->depth() == start_depth + 1) {
       // Clear the current policies when exiting the <policy> tags
-      current_policies = OverlayableItem::Policy::kNone;
+      current_policies = PolicyFlags::NONE;
       continue;
     } else if (event == xml::XmlPullParser::Event::kComment) {
       // Retrieve the comment of individual <item> tags
@@ -1088,7 +1092,7 @@
     const std::string& element_name = parser->element_name();
     const std::string& element_namespace = parser->element_namespace();
     if (element_namespace.empty() && element_name == "item") {
-      if (current_policies == OverlayableItem::Policy::kNone) {
+      if (current_policies == PolicyFlags::NONE) {
         diag_->Error(DiagMessage(element_source)
                          << "<item> within an <overlayable> must be inside a <policy> block");
         error = true;
@@ -1133,7 +1137,7 @@
       out_resource->child_resources.push_back(std::move(child_resource));
 
     } else if (element_namespace.empty() && element_name == "policy") {
-      if (current_policies != OverlayableItem::Policy::kNone) {
+      if (current_policies != PolicyFlags::NONE) {
         // If the policy list is not empty, then we are currently inside a policy element
         diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
         error = true;
@@ -1141,21 +1145,14 @@
       } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
         // Parse the polices separated by vertical bar characters to allow for specifying multiple
         // policies. Items within the policy tag will have the specified policy.
-        static const auto kPolicyMap =
-            ImmutableMap<StringPiece, OverlayableItem::Policy>::CreatePreSorted({
-                {"odm", OverlayableItem::Policy::kOdm},
-                {"oem", OverlayableItem::Policy::kOem},
-                {"product", OverlayableItem::Policy::kProduct},
-                {"public", OverlayableItem::Policy::kPublic},
-                {"signature", OverlayableItem::Policy::kSignature},
-                {"system", OverlayableItem::Policy::kSystem},
-                {"vendor", OverlayableItem::Policy::kVendor},
-            });
-
         for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) {
           StringPiece trimmed_part = util::TrimWhitespace(part);
-          const auto policy = kPolicyMap.find(trimmed_part);
-          if (policy == kPolicyMap.end()) {
+          const auto policy = std::find_if(kPolicyStringToFlag.begin(),
+                                           kPolicyStringToFlag.end(),
+                                           [trimmed_part](const auto& it) {
+                                             return trimmed_part == it.first;
+                                           });
+          if (policy == kPolicyStringToFlag.end()) {
             diag_->Error(DiagMessage(element_source)
                          << "<policy> has unsupported type '" << trimmed_part << "'");
             error = true;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 24531bc..9b70079 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -41,6 +41,8 @@
 using ::testing::SizeIs;
 using ::testing::StrEq;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
@@ -959,7 +961,7 @@
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE));
 
   search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
   ASSERT_TRUE(search_result);
@@ -968,7 +970,7 @@
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE));
 }
 
 TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
@@ -1005,6 +1007,9 @@
         <policy type="oem">
           <item type="string" name="buz" />
         </policy>
+        <policy type="actor">
+          <item type="string" name="actor" />
+        </policy>
       </overlayable>)";
   ASSERT_TRUE(TestParse(input));
 
@@ -1014,7 +1019,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
   ASSERT_TRUE(search_result);
@@ -1022,7 +1027,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
   ASSERT_TRUE(search_result);
@@ -1030,7 +1035,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::VENDOR_PARTITION));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
   ASSERT_TRUE(search_result);
@@ -1038,7 +1043,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PUBLIC));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/foz"));
   ASSERT_TRUE(search_result);
@@ -1046,7 +1051,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/biz"));
   ASSERT_TRUE(search_result);
@@ -1054,7 +1059,7 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOdm));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::ODM_PARTITION));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/buz"));
   ASSERT_TRUE(search_result);
@@ -1062,7 +1067,15 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOem));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::OEM_PARTITION));
+
+  search_result = table_.FindResource(test::ParseNameOrDie("string/actor"));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::ACTOR_SIGNATURE));
 }
 
 TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) {
@@ -1125,8 +1138,8 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
-                                                   | OverlayableItem::Policy::kPublic));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::VENDOR_PARTITION
+                                                   | PolicyFlags::PUBLIC));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
   ASSERT_TRUE(search_result);
@@ -1134,8 +1147,8 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
-                                                   | OverlayableItem::Policy::kSystem));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION
+                                                   | PolicyFlags::SYSTEM_PARTITION));
 }
 
 TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 30ba1ae..93a7a31 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -36,6 +36,8 @@
 #include <unordered_map>
 #include <vector>
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 // The Public status of a resource.
@@ -75,36 +77,8 @@
 struct OverlayableItem {
   explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable)
       : overlayable(overlayable) {}
-
-  // Represents the types overlays that are allowed to overlay the resource.
-  typedef uint32_t PolicyFlags;
-  enum Policy : uint32_t {
-    kNone = 0x00000000,
-
-    // The resource can be overlaid by any overlay.
-    kPublic = 0x00000001,
-
-    // The resource can be overlaid by any overlay on the system partition.
-    kSystem = 0x00000002,
-
-    // The resource can be overlaid by any overlay on the vendor partition.
-    kVendor = 0x00000004,
-
-    // The resource can be overlaid by any overlay on the product partition.
-    kProduct = 0x00000008,
-
-    // The resource can be overlaid by any overlay signed with the same signature as its actor.
-    kSignature = 0x00000010,
-
-    // The resource can be overlaid by any overlay on the odm partition.
-    kOdm = 0x00000020,
-
-    // The resource can be overlaid by any overlay on the oem partition.
-    kOem = 0x00000040,
-  };
-
   std::shared_ptr<Overlayable> overlayable;
-  PolicyFlags policies = Policy::kNone;
+  PolicyFlags policies = PolicyFlags::NONE;
   std::string comment;
   Source source;
 };
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index b97dc6b..9271a7e 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -30,6 +30,8 @@
 using ::testing::NotNull;
 using ::testing::StrEq;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 TEST(ResourceTableTest, FailToAddResourceWithBadName) {
@@ -247,8 +249,8 @@
   auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme",
                                                    Source("res/values/overlayable.xml", 40));
   OverlayableItem overlayable_item(overlayable);
-  overlayable_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
   overlayable_item.comment = "comment";
   overlayable_item.source = Source("res/values/overlayable.xml", 42);
 
@@ -264,8 +266,8 @@
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
-                                                   | OverlayableItem::Policy::kVendor));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION
+                                                   | PolicyFlags::VENDOR_PARTITION));
   ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.source.line, 42);
@@ -277,17 +279,17 @@
   const ResourceName foo = test::ParseNameOrDie("android:string/foo");
   auto group = std::make_shared<Overlayable>("Name", "overlay://theme");
   OverlayableItem overlayable(group);
-  overlayable.policies = OverlayableItem::Policy::kProduct;
+  overlayable.policies = PolicyFlags::PRODUCT_PARTITION;
   ASSERT_TRUE(table.SetOverlayable(foo, overlayable, test::GetDiagnostics()));
 
   const ResourceName bar = test::ParseNameOrDie("android:string/bar");
   OverlayableItem overlayable2(group);
-  overlayable2.policies = OverlayableItem::Policy::kProduct;
+  overlayable2.policies = PolicyFlags::PRODUCT_PARTITION;
   ASSERT_TRUE(table.SetOverlayable(bar, overlayable2, test::GetDiagnostics()));
 
   const ResourceName baz = test::ParseNameOrDie("android:string/baz");
   OverlayableItem overlayable3(group);
-  overlayable3.policies = OverlayableItem::Policy::kVendor;
+  overlayable3.policies = PolicyFlags::VENDOR_PARTITION;
   ASSERT_TRUE(table.SetOverlayable(baz, overlayable3, test::GetDiagnostics()));
 }
 
@@ -296,12 +298,12 @@
 
   const ResourceName foo = test::ParseNameOrDie("android:string/foo");
   OverlayableItem overlayable_item(std::make_shared<Overlayable>("Name", "overlay://theme"));
-  overlayable_item.policies = OverlayableItem::Policy::kProduct;
+  overlayable_item.policies = PolicyFlags::PRODUCT_PARTITION;
   ASSERT_TRUE(table.SetOverlayable(foo, overlayable_item, test::GetDiagnostics()));
 
   const ResourceName bar = test::ParseNameOrDie("android:string/bar");
   OverlayableItem overlayable_item2(std::make_shared<Overlayable>("Name2",  "overlay://theme"));
-  overlayable_item2.policies = OverlayableItem::Policy::kProduct;
+  overlayable_item2.policies = PolicyFlags::PRODUCT_PARTITION;
   ASSERT_TRUE(table.SetOverlayable(bar, overlayable_item2, test::GetDiagnostics()));
 }
 
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 8a2f5af..ab9ce66 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -167,6 +167,7 @@
     SIGNATURE = 5;
     ODM = 6;
     OEM = 7;
+    ACTOR = 8;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 5b6935b..bf886c2 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1766,9 +1766,12 @@
       return 1;
     }
 
-    // First extract the Package name without modifying it (via --rename-manifest-package).
-    if (Maybe<AppInfo> maybe_app_info =
+    // Determine the package name under which to merge resources.
+    if (options_.rename_resources_package) {
+      context_->SetCompilationPackage(options_.rename_resources_package.value());
+    } else if (Maybe<AppInfo> maybe_app_info =
             ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) {
+      // Extract the package name from the manifest ignoring the value of --rename-manifest-package.
       const AppInfo& app_info = maybe_app_info.value();
       context_->SetCompilationPackage(app_info.package);
     }
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 4722358..e7be434 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -45,6 +45,7 @@
   bool auto_add_overlay = false;
   bool override_styles_instead_of_overlaying = false;
   OutputFormat output_format = OutputFormat::kApk;
+  Maybe<std::string> rename_resources_package;
 
   // Java/Proguard options.
   Maybe<std::string> generate_java_class_path;
@@ -256,6 +257,8 @@
         &options_.override_styles_instead_of_overlaying);
     AddOptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.",
         &options_.manifest_fixer_options.rename_manifest_package);
+    AddOptionalFlag("--rename-resources-package", "Renames the package in resources table",
+        &options_.rename_resources_package);
     AddOptionalFlag("--rename-instrumentation-target-package",
         "Changes the name of the target package for instrumentation. Most useful\n"
             "when used in conjunction with --rename-manifest-package.",
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index fcd6aaa..f362744 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -455,35 +455,6 @@
       const ResTable_overlayable_policy_header* policy_header =
           ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
 
-      OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone;
-      if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) {
-        policies |= OverlayableItem::Policy::kPublic;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) {
-        policies |= OverlayableItem::Policy::kSystem;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) {
-        policies |= OverlayableItem::Policy::kVendor;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
-        policies |= OverlayableItem::Policy::kProduct;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_SIGNATURE) {
-        policies |= OverlayableItem::Policy::kSignature;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_ODM_PARTITION) {
-        policies |= OverlayableItem::Policy::kOdm;
-      }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_OEM_PARTITION) {
-        policies |= OverlayableItem::Policy::kOem;
-      }
-
       const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
           ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
       const ResTable_ref* const ref_end = ref_begin
@@ -501,7 +472,7 @@
         }
 
         OverlayableItem overlayable_item(overlayable);
-        overlayable_item.policies = policies;
+        overlayable_item.policies = policy_header->policy_flags;
         if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
           return false;
         }
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index cbce8a5..4784ecf 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -233,7 +233,7 @@
 struct OverlayableChunk {
   std::string actor;
   Source source;
-  std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
+  std::map<PolicyFlags, std::set<ResourceId>> policy_ids;
 };
 
 class PackageFlattener {
@@ -493,35 +493,12 @@
           return false;
         }
 
-        uint32_t policy_flags = 0;
-        if (item.policies & OverlayableItem::Policy::kPublic) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-        if (item.policies & OverlayableItem::Policy::kSystem) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
-        }
-        if (item.policies & OverlayableItem::Policy::kVendor) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
-        }
-        if (item.policies & OverlayableItem::Policy::kProduct) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
-        }
-        if (item.policies & OverlayableItem::Policy::kSignature) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE;
-        }
-        if (item.policies & OverlayableItem::Policy::kOdm) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_ODM_PARTITION;
-        }
-        if (item.policies & OverlayableItem::Policy::kOem) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_OEM_PARTITION;
-        }
-
-        auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+        auto policy = overlayable_chunk->policy_ids.find(item.policies);
         if (policy != overlayable_chunk->policy_ids.end()) {
           policy->second.insert(id);
         } else {
           overlayable_chunk->policy_ids.insert(
-              std::make_pair(policy_flags, std::set<ResourceId>{id}));
+              std::make_pair(item.policies, std::set<ResourceId>{id}));
         }
       }
     }
@@ -559,7 +536,8 @@
         ChunkWriter policy_writer(buffer);
         auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
             RES_TABLE_OVERLAYABLE_POLICY_TYPE);
-        policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+        policy_type->policy_flags =
+            static_cast<PolicyFlags>(util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)));
         policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
                                                             policy_ids.second.size()));
         // Write the ids after the policy header
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index af2293f..59627ce 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -32,6 +32,8 @@
 using ::testing::IsNull;
 using ::testing::NotNull;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 class TableFlattenerTest : public ::testing::Test {
@@ -671,9 +673,9 @@
 
 TEST_F(TableFlattenerTest, FlattenOverlayable) {
   OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
-  overlayable_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_item.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION;
+  overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
 
   std::string name = "com.app.test:integer/overlayable";
   std::unique_ptr<ResourceTable> table =
@@ -691,27 +693,27 @@
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(result_overlayable_item.policies, OverlayableItem::Policy::kSystem
-                                         | OverlayableItem::Policy::kVendor
-                                         | OverlayableItem::Policy::kProduct);
+  EXPECT_EQ(result_overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION
+                                         | PolicyFlags::VENDOR_PARTITION
+                                         | PolicyFlags::PRODUCT_PARTITION);
 }
 
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
   auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
   std::string name_zero = "com.app.test:integer/overlayable_zero_item";
   OverlayableItem overlayable_item_zero(overlayable);
-  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION;
 
   std::string name_one = "com.app.test:integer/overlayable_one_item";
   OverlayableItem overlayable_item_one(overlayable);
-  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+  overlayable_item_one.policies |= PolicyFlags::PUBLIC;
 
   std::string name_two = "com.app.test:integer/overlayable_two_item";
   OverlayableItem overlayable_item_two(overlayable);
-  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item_two.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item_two.policies |= PolicyFlags::SYSTEM_PARTITION;
+  overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION;
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
@@ -732,47 +734,48 @@
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
-                                       | OverlayableItem::Policy::kProduct);
+  EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION
+                                       | PolicyFlags::PRODUCT_PARTITION);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(overlayable_item.policies, PolicyFlags::PUBLIC);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
-                                       | OverlayableItem::Policy::kProduct
-                                       | OverlayableItem::Policy::kVendor);
+  EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION
+                                       | PolicyFlags::PRODUCT_PARTITION
+                                       | PolicyFlags::VENDOR_PARTITION);
 }
 
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
   auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
   std::string name_zero = "com.app.test:integer/overlayable_zero";
   OverlayableItem overlayable_item_zero(group);
-  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION;
 
   auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
   std::string name_one = "com.app.test:integer/overlayable_one";
   OverlayableItem overlayable_item_one(group_one);
-  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+  overlayable_item_one.policies |= PolicyFlags::PUBLIC;
 
   std::string name_two = "com.app.test:integer/overlayable_two";
   OverlayableItem overlayable_item_two(group);
-  overlayable_item_two.policies |= OverlayableItem::Policy::kOdm;
-  overlayable_item_two.policies |= OverlayableItem::Policy::kOem;
-  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item_two.policies |= PolicyFlags::ODM_PARTITION;
+  overlayable_item_two.policies |= PolicyFlags::OEM_PARTITION;
+  overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION;
 
   std::string name_three = "com.app.test:integer/overlayable_three";
   OverlayableItem overlayable_item_three(group_one);
-  overlayable_item_three.policies |= OverlayableItem::Policy::kSignature;
+  overlayable_item_three.policies |= PolicyFlags::SIGNATURE;
+  overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE;
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
@@ -796,8 +799,8 @@
   OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
-                                         | OverlayableItem::Policy::kProduct);
+  EXPECT_EQ(result_overlayable.policies, PolicyFlags::SYSTEM_PARTITION
+                                         | PolicyFlags::PRODUCT_PARTITION);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
   ASSERT_TRUE(search_result);
@@ -806,7 +809,7 @@
   result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(result_overlayable.policies, PolicyFlags::PUBLIC);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
   ASSERT_TRUE(search_result);
@@ -815,9 +818,9 @@
   result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kOdm
-                                         | OverlayableItem::Policy::kOem
-                                         | OverlayableItem::Policy::kVendor);
+  EXPECT_EQ(result_overlayable.policies, PolicyFlags::ODM_PARTITION
+                                         | PolicyFlags::OEM_PARTITION
+                                         | PolicyFlags::VENDOR_PARTITION);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
   ASSERT_TRUE(search_result);
@@ -826,7 +829,8 @@
   result_overlayable = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
   EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
-  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature);
+  EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE
+                                           | PolicyFlags::ACTOR_SIGNATURE);
 }
 
 TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 4cd6e93..2fd01d7 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -30,6 +30,8 @@
 using ::android::LocaleValue;
 using ::android::ResStringPool;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 namespace {
@@ -379,25 +381,28 @@
   for (const int policy : pb_overlayable.policy()) {
     switch (policy) {
       case pb::OverlayableItem::PUBLIC:
-        out_overlayable->policies |= OverlayableItem::Policy::kPublic;
+        out_overlayable->policies |= PolicyFlags::PUBLIC;
         break;
       case pb::OverlayableItem::SYSTEM:
-        out_overlayable->policies |= OverlayableItem::Policy::kSystem;
+        out_overlayable->policies |= PolicyFlags::SYSTEM_PARTITION;
         break;
       case pb::OverlayableItem::VENDOR:
-        out_overlayable->policies |= OverlayableItem::Policy::kVendor;
+        out_overlayable->policies |= PolicyFlags::VENDOR_PARTITION;
         break;
       case pb::OverlayableItem::PRODUCT:
-        out_overlayable->policies |= OverlayableItem::Policy::kProduct;
+        out_overlayable->policies |= PolicyFlags::PRODUCT_PARTITION;
         break;
       case pb::OverlayableItem::SIGNATURE:
-        out_overlayable->policies |= OverlayableItem::Policy::kSignature;
+        out_overlayable->policies |= PolicyFlags::SIGNATURE;
         break;
       case pb::OverlayableItem::ODM:
-        out_overlayable->policies |= OverlayableItem::Policy::kOdm;
+        out_overlayable->policies |= PolicyFlags::ODM_PARTITION;
         break;
       case pb::OverlayableItem::OEM:
-        out_overlayable->policies |= OverlayableItem::Policy::kOem;
+        out_overlayable->policies |= PolicyFlags::OEM_PARTITION;
+        break;
+      case pb::OverlayableItem::ACTOR:
+        out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE;
         break;
       default:
         *out_error = "unknown overlayable policy";
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index d9f6c19..ba6df22 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -21,6 +21,8 @@
 
 using android::ConfigDescription;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) {
@@ -299,27 +301,30 @@
   pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
   pb_overlayable_item->set_overlayable_idx(i);
 
-  if (overlayable_item.policies & OverlayableItem::Policy::kPublic) {
+  if (overlayable_item.policies & PolicyFlags::PUBLIC) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
+  if (overlayable_item.policies & PolicyFlags::PRODUCT_PARTITION) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
+  if (overlayable_item.policies & PolicyFlags::SYSTEM_PARTITION) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
+  if (overlayable_item.policies & PolicyFlags::VENDOR_PARTITION) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kSignature) {
+  if (overlayable_item.policies & PolicyFlags::SIGNATURE) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kOdm) {
+  if (overlayable_item.policies & PolicyFlags::ODM_PARTITION) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::ODM);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kOem) {
+  if (overlayable_item.policies & PolicyFlags::OEM_PARTITION) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::OEM);
   }
+  if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
+    pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR);
+  }
 
   if (source_pool != nullptr) {
     SerializeSourceToPb(overlayable_item.source, source_pool,
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 61a8335..1a7de6d 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -28,6 +28,8 @@
 using ::testing::SizeIs;
 using ::testing::StrEq;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 class MockFileCollection : public io::IFileCollection {
@@ -171,7 +173,7 @@
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::NONE));
   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.source.line, Eq(42));
 }
@@ -516,23 +518,28 @@
 TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
   OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>(
       "CustomizableResources", "overlay://customization"));
-  overlayable_item_foo.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_item_foo.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_foo.policies |= PolicyFlags::SYSTEM_PARTITION;
+  overlayable_item_foo.policies |= PolicyFlags::PRODUCT_PARTITION;
 
   OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
       "TaskBar", "overlay://theme"));
-  overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item_bar.policies |= PolicyFlags::PUBLIC;
+  overlayable_item_bar.policies |= PolicyFlags::VENDOR_PARTITION;
 
   OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
       "FontPack", "overlay://theme"));
-  overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic;
+  overlayable_item_baz.policies |= PolicyFlags::PUBLIC;
 
   OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
       "IconPack", "overlay://theme"));
-  overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature;
-  overlayable_item_boz.policies |= OverlayableItem::Policy::kOdm;
-  overlayable_item_boz.policies |= OverlayableItem::Policy::kOem;
+  overlayable_item_boz.policies |= PolicyFlags::SIGNATURE;
+  overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION;
+  overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION;
+
+  OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>(
+      "ActorConfig", "overlay://theme"));
+  overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE;
+  overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE;
 
   OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
       "Other", "overlay://customization"));
@@ -546,6 +553,7 @@
           .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
           .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz)
           .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
+          .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config)
           .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
           .Build();
 
@@ -565,8 +573,8 @@
   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem
-                                              | OverlayableItem::Policy::kProduct));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION
+                                              | PolicyFlags::PRODUCT_PARTITION));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
   ASSERT_TRUE(search_result);
@@ -574,8 +582,8 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
-                                              | OverlayableItem::Policy::kVendor));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC
+                                              | PolicyFlags::VENDOR_PARTITION));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
   ASSERT_TRUE(search_result);
@@ -583,7 +591,7 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz"));
   ASSERT_TRUE(search_result);
@@ -591,16 +599,25 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature
-                                            | OverlayableItem::Policy::kOdm
-                                            | OverlayableItem::Policy::kOem));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
+                                            | PolicyFlags::ODM_PARTITION
+                                            | PolicyFlags::OEM_PARTITION));
+
+  search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config"));
+  ASSERT_TRUE(search_result);
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  overlayable_item = search_result.value().entry->overlayable_item.value();
+  EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig"));
+  EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE
+                                            | PolicyFlags::ACTOR_SIGNATURE));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+  EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::NONE));
   EXPECT_THAT(overlayable_item.comment, Eq("comment"));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 0be4ccf..69cf5ee 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -29,6 +29,8 @@
 using ::testing::StrEq;
 using ::testing::UnorderedElementsAreArray;
 
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+
 namespace aapt {
 
 struct TableMergerTest : public ::testing::Test {
@@ -487,8 +489,8 @@
   auto overlayable = std::make_shared<Overlayable>("CustomizableResources",
                                                   "overlay://customization");
   OverlayableItem overlayable_item(overlayable);
-  overlayable_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item.policies |= OverlayableItem::Policy::kVendor;
+  overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
 
   std::unique_ptr<ResourceTable> table_a =
       test::ResourceTableBuilder()
@@ -516,8 +518,8 @@
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
-                                                   | OverlayableItem::Policy::kVendor));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION
+                                                   | PolicyFlags::VENDOR_PARTITION));
 }
 
 TEST_F(TableMergerTest, SetOverlayableLater) {
@@ -530,8 +532,8 @@
           .Build();
 
   OverlayableItem overlayable_item(overlayable);
-  overlayable_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_item.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item.policies |= PolicyFlags::PUBLIC;
+  overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -552,15 +554,15 @@
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
-                                                   | OverlayableItem::Policy::kSystem));
+  EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PUBLIC
+                                                   | PolicyFlags::SYSTEM_PARTITION));
 }
 
 TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
   auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
                                                          "overlay://customization");
   OverlayableItem overlayable_item_first(overlayable_first);
-  overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_a =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -570,7 +572,7 @@
   auto overlayable_second = std::make_shared<Overlayable>("ThemeResources",
                                                           "overlay://customization");
   OverlayableItem overlayable_item_second(overlayable_second);
-  overlayable_item_second.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -589,7 +591,7 @@
   auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
                                                          "overlay://customization");
   OverlayableItem overlayable_item_first(overlayable_first);
-  overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_a =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -599,7 +601,7 @@
   auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources",
                                                           "overlay://theme");
   OverlayableItem overlayable_item_second(overlayable_second);
-  overlayable_item_second.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -618,7 +620,7 @@
   auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources",
                                                          "overlay://customization");
   OverlayableItem overlayable_item_first(overlayable_first);
-  overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_a =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -628,7 +630,7 @@
   auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources",
                                                           "overlay://customization");
   OverlayableItem overlayable_item_second(overlayable_second);
-  overlayable_item_second.policies |= OverlayableItem::Policy::kSignature;
+  overlayable_item_second.policies |= PolicyFlags::SIGNATURE;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -648,7 +650,7 @@
                                                   "overlay://customization");
 
   OverlayableItem overlayable_item_first(overlayable);
-  overlayable_item_first.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_a =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -656,7 +658,7 @@
           .Build();
 
   OverlayableItem overlayable_item_second(overlayable);
-  overlayable_item_second.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
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/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index c48e895..0229b84 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1713,7 +1713,7 @@
          * @return network disable reason string, or null if the reason is invalid.
          */
         @Nullable
-        public static String getNetworkDisableReasonString(
+        public static String getNetworkSelectionDisableReasonString(
                 @NetworkSelectionDisableReason int reason) {
             DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason);
             if (info == null) {
@@ -1727,8 +1727,8 @@
          * @return current network disable reason in String (for debug purpose)
          * @hide
          */
-        public String getNetworkDisableReasonString() {
-            return getNetworkDisableReasonString(mNetworkSelectionDisableReason);
+        public String getNetworkSelectionDisableReasonString() {
+            return getNetworkSelectionDisableReasonString(mNetworkSelectionDisableReason);
         }
 
         /**
@@ -2189,17 +2189,21 @@
 
 
         sbuf.append(" NetworkSelectionStatus ")
-                .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
+                .append(mNetworkSelectionStatus.getNetworkStatusString())
+                .append("\n");
         if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
             sbuf.append(" mNetworkSelectionDisableReason ")
-                    .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
+                    .append(mNetworkSelectionStatus.getNetworkSelectionDisableReasonString())
+                    .append("\n");
 
             for (int index = NetworkSelectionStatus.DISABLED_NONE;
                     index < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
                 if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
-                    sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
-                            + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
-                            + "\n");
+                    sbuf.append(
+                            NetworkSelectionStatus.getNetworkSelectionDisableReasonString(index))
+                            .append(" counter:")
+                            .append(mNetworkSelectionStatus.getDisableReasonCounter(index))
+                            .append("\n");
                 }
             }
         }
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..48526ab 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;
@@ -1881,9 +1880,11 @@
      * NOTE:
      * <li> These networks are just a suggestion to the platform. The platform will ultimately
      * decide on which network the device connects to. </li>
-     * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
-     * currently connected to a suggested network which is being removed then the device will
-     * disconnect from that network.</li>
+     * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
+     * If the device is currently connected to a suggested network which is being removed then the
+     * device will disconnect from that network.</li>
+     * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
+     * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
      * <li> In-place modification of existing suggestions are allowed.
      * If the provided suggestions {@link WifiNetworkSuggestion#equals(Object)} any previously
      * provided suggestions by the app. Previous suggestions will be updated</li>
@@ -5994,11 +5995,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 +6024,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);
+    }
 }