Merge "Mainline: remove usage of hidden DEFAULT_PHONE_INDEX"
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/Android.bp b/Android.bp
index 04b4e6e..3308768 100644
--- a/Android.bp
+++ b/Android.bp
@@ -217,7 +217,9 @@
         // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
         // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
         // to a separate package.
-        "wifi/java/android/net/wifi/WifiNetworkScoreCache.java"
+        "wifi/java/android/net/wifi/WifiNetworkScoreCache.java",
+        "wifi/java/android/net/wifi/WifiCondManager.java",
+        "wifi/java/android/net/wifi/wificond/*.java",
     ],
 }
 
@@ -247,6 +249,7 @@
         ":framework-telephony-sources",
         ":framework-wifi-sources",
         ":framework-wifi-non-updatable-sources",
+	":libwificond_ipc_aidl",
         ":PacProcessor-aidl-sources",
         ":ProxyHandler-aidl-sources",
 
@@ -371,6 +374,9 @@
         "com.android.sysprop.apex",
         "PlatformProperties",
     ],
+    aidl: {
+        include_dirs: ["system/connectivity/wificond/aidl"],
+    },
     sdk_version: "core_platform",
     installable: false,
 }
@@ -478,7 +484,8 @@
     installable: false, // this lib is a build-only library
     static_libs: [
         "framework-minus-apex",
-        // TODO(jiyong): add stubs for APEXes here
+        "framework-sdkext-stubs-systemapi",
+        // TODO(jiyong): add more stubs for APEXes here
     ],
     sdk_version: "core_platform",
     apex_available: ["//apex_available:platform"],
@@ -804,8 +811,8 @@
 filegroup {
     name: "incremental_aidl",
     srcs: [
+        "core/java/android/os/incremental/IIncrementalManagerNative.aidl",
         "core/java/android/os/incremental/IIncrementalManager.aidl",
-        "core/java/android/os/incremental/IIncrementalServiceProxy.aidl",
         "core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
         "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
         "core/java/android/os/incremental/NamedParcelFileDescriptor.aidl",
@@ -1172,7 +1179,7 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) ",
     write_sdk_values: true,
 }
 
@@ -1483,7 +1490,7 @@
     merge_annotations_dirs: [
         "metalava-manual",
     ],
-    args: " --show-annotation android.annotation.SystemApi",
+    args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)",
 }
 
 java_library_static {
@@ -1505,7 +1512,7 @@
     removed_dex_api_filename: "removed-dex.txt",
     args: metalava_framework_docs_args +
         " --show-unannotated " +
-        " --show-annotation android.annotation.SystemApi " +
+        " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
         " --show-annotation android.annotation.TestApi ",
 }
 
@@ -1524,7 +1531,7 @@
         " --hide ReferencesHidden " +
         " --hide UnhiddenSystemApi " +
         " --show-unannotated " +
-        " --show-annotation android.annotation.SystemApi " +
+        " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
         " --show-annotation android.annotation.TestApi ",
 }
 
@@ -1568,7 +1575,7 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi",
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)",
     check_api: {
         current: {
             api_file: "api/system-current.txt",
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 8fac394..f94de29 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -256,6 +256,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ext.jar)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/google/android/mms)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/*-service.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/service-statsd.jar)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6831117..78e72bf 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,13 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               cmds/hid/
+               cmds/input/
+               libs/input/
+
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 
diff --git a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
index c096cd2..4ed3b4e 100644
--- a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java
@@ -95,7 +95,7 @@
 
         mTraceMarkParser.forAllSlices((key, slices) -> {
             for (TraceMarkSlice slice : slices) {
-                state.addExtraResult(key, (long) (slice.getDurarionInSeconds() * NANOS_PER_S));
+                state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
             }
         });
 
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index b075239..fe2b1f6 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -23,11 +23,15 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -140,6 +144,8 @@
     /** @see #addExtraResult(String, long) */
     private ArrayMap<String, ArrayList<Long>> mExtraResults;
 
+    private final List<Long> mTmpDurations = Arrays.asList(0L);
+
     // Statistics. These values will be filled when the benchmark has finished.
     // The computation needs double precision, but long int is fine for final reporting.
     private Stats mStats;
@@ -188,14 +194,25 @@
         if (duration < 0) {
             throw new RuntimeException("duration is negative: " + duration);
         }
+        mTmpDurations.set(0, duration);
+        return keepRunning(mTmpDurations);
+    }
+
+    /**
+     * Similar to the {@link #keepRunning(long)} but accepts a list of durations
+     */
+    public boolean keepRunning(List<Long> durations) {
         switch (mState) {
             case NOT_STARTED:
                 mState = WARMUP;
                 mWarmupStartTime = System.nanoTime();
                 return true;
             case WARMUP: {
+                if (ArrayUtils.isEmpty(durations)) {
+                    return true;
+                }
                 final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
-                ++mWarmupIterations;
+                mWarmupIterations += durations.size();
                 if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
                         && timeSinceStartingWarmup >= mWarmupDurationNs) {
                     beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
@@ -203,7 +220,10 @@
                 return true;
             }
             case RUNNING: {
-                mResults.add(duration);
+                if (ArrayUtils.isEmpty(durations)) {
+                    return true;
+                }
+                mResults.addAll(durations);
                 final boolean keepRunning = mResults.size() < mMaxIterations;
                 if (!keepRunning) {
                     mStats = new Stats(mResults);
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
index 1afed3a..b15b6f6 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java
@@ -40,6 +40,8 @@
 
     private final Predicate<TraceMarkLine> mTraceLineFilter;
 
+    private static final long MICROS_PER_SECOND = 1000L * 1000L;
+
     public TraceMarkParser(Predicate<TraceMarkLine> traceLineFilter) {
         mTraceLineFilter = traceLineFilter;
     }
@@ -116,13 +118,19 @@
         }
     }
 
+    public void reset() {
+        mSlicesMap.clear();
+        mDepthMap.clear();
+        mPendingStarts.clear();
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         forAllSlices((key, slices) -> {
             double totalMs = 0;
             for (TraceMarkSlice s : slices) {
-                totalMs += s.getDurarionInSeconds() * 1000;
+                totalMs += s.getDurationInSeconds() * 1000;
             }
             sb.append(key).append(" count=").append(slices.size()).append(" avg=")
                     .append(totalMs / slices.size()).append("ms\n");
@@ -134,6 +142,10 @@
         return sb.toString();
     }
 
+    static double microsecondToSeconds(long ms) {
+        return (ms * 1.0d) / MICROS_PER_SECOND;
+    }
+
     public static class TraceMarkSlice {
         public final TraceMarkLine begin;
         public final TraceMarkLine end;
@@ -143,7 +155,11 @@
             this.end = end;
         }
 
-        public double getDurarionInSeconds() {
+        public double getDurationInSeconds() {
+            return microsecondToSeconds(end.timestamp - begin.timestamp);
+        }
+
+        public long getDurationInMicroseconds() {
             return end.timestamp - begin.timestamp;
         }
     }
@@ -164,7 +180,7 @@
         static final char SYNC_END = 'E';
 
         public final String taskPid;
-        public final double timestamp;
+        public final long timestamp; // in microseconds
         public final String name;
         public final boolean isAsync;
         public final boolean isBegin;
@@ -179,7 +195,7 @@
             if (timeBegin < 0) {
                 throw new IllegalArgumentException("Timestamp start not found");
             }
-            timestamp = Double.parseDouble(rawLine.substring(timeBegin, timeEnd));
+            timestamp = parseMicroseconds(rawLine.substring(timeBegin, timeEnd));
             isAsync = type == ASYNC_START || type == ASYNC_FINISH;
             isBegin = type == ASYNC_START || type == SYNC_BEGIN;
 
@@ -223,9 +239,29 @@
             return null;
         }
 
+        /**
+         * Parse the timestamp from atrace output, the format will be like:
+         * 84962.920719  where the decimal part will be always exactly 6 digits.
+         * ^^^^^ ^^^^^^
+         * |     |
+         * sec   microsec
+         */
+        static long parseMicroseconds(String line) {
+            int end = line.length();
+            long t = 0;
+            for (int i = 0; i < end; i++) {
+                char c = line.charAt(i);
+                if (c >= '0' && c <= '9') {
+                    t = t * 10 + (c - '0');
+                }
+            }
+            return t;
+        }
+
         @Override
         public String toString() {
-            return "TraceMarkLine{pid=" + taskPid + " time=" + timestamp + " name=" + name
+            return "TraceMarkLine{pid=" + taskPid + " time="
+                    + microsecondToSeconds(timestamp) + " name=" + name
                     + " async=" + isAsync + " begin=" + isBegin + "}";
         }
     }
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..9ea3953
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,39 @@
+// 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.
+
+mainline_stubs_args =
+    "--error UnhiddenSystemApi " +
+    "--hide BroadcastBehavior " +
+    "--hide DeprecationMismatch " +
+    "--hide HiddenSuperclass " +
+    "--hide HiddenTypedefConstant " +
+    "--hide HiddenTypeParameter " +
+    "--hide MissingPermission " +
+    "--hide RequiresPermission " +
+    "--hide SdkConstant " +
+    "--hide Todo " +
+    "--hide Typo " +
+    "--hide UnavailableSymbol "
+
+stubs_defaults {
+    name: "framework-module-stubs-defaults-publicapi",
+    args: mainline_stubs_args,
+    installable: false,
+}
+
+stubs_defaults {
+    name: "framework-module-stubs-defaults-systemapi",
+    args: mainline_stubs_args + " --show-annotation android.annotation.SystemApi ",
+    installable: false,
+}
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
index aaf25b1..b9071f8 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkext/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_visibility: [":__subpackages__"],
+}
+
 apex {
     name: "com.android.sdkext",
     manifest: "manifest.json",
@@ -25,6 +29,11 @@
     certificate: ":com.android.sdkext.certificate",
 }
 
+sdk {
+    name: "sdkext-sdk",
+    java_libs: [ "framework-sdkext-stubs-systemapi" ],
+}
+
 apex_key {
     name: "com.android.sdkext.key",
     public_key: "com.android.sdkext.avbpubkey",
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkext/framework/Android.bp
index b17f0f8..a50dc3d 100644
--- a/apex/sdkext/framework/Android.bp
+++ b/apex/sdkext/framework/Android.bp
@@ -12,12 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_visibility: [ ":__pkg__" ]
+}
+
 filegroup {
     name: "framework-sdkext-sources",
     srcs: [
         "java/**/*.java",
     ],
     path: "java",
+    visibility: [ "//frameworks/base:__pkg__" ] // For the "global" stubs.
 }
 
 java_library {
@@ -27,4 +32,40 @@
     libs: [ "framework-annotations-lib" ],
     permitted_packages: [ "android.os.ext" ],
     installable: true,
+    visibility: [ "//frameworks/base/apex/sdkext:__pkg__" ],
+}
+
+droidstubs {
+    name: "framework-sdkext-droidstubs-publicapi",
+    defaults: [
+        "framework-sdkext-stubs-defaults",
+        "framework-module-stubs-defaults-publicapi",
+    ]
+}
+
+droidstubs {
+    name: "framework-sdkext-droidstubs-systemapi",
+    defaults: [
+        "framework-sdkext-stubs-defaults",
+        "framework-module-stubs-defaults-systemapi",
+    ]
+}
+
+stubs_defaults {
+    name: "framework-sdkext-stubs-defaults",
+    srcs: [
+        ":framework-sdkext-sources",
+        ":framework-annotations",
+    ],
+    sdk_version: "system_current",
+}
+
+java_library {
+    name: "framework-sdkext-stubs-systemapi",
+    srcs: [":framework-sdkext-droidstubs-systemapi"],
+    sdk_version: "system_current",
+    visibility: [
+      "//frameworks/base:__pkg__", // Framework
+      "//frameworks/base/apex/sdkext:__pkg__", // sdkext SDK
+    ]
 }
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 8327f31..5c46e1f 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -16,15 +16,13 @@
     name: "com.android.os.statsd",
     defaults: ["com.android.os.statsd-defaults"],
     manifest: "apex_manifest.json",
-
-
 }
 
 apex_defaults {
     // libc.so and libcutils.so are included in the apex
     // native_shared_libs: ["libc", "libcutils"],
     // binaries: ["vold"],
-    // java_libs: ["core-all"],
+    java_libs: ["service-statsd"],
     // prebuilts: ["my_prebuilt"],
     name: "com.android.os.statsd-defaults",
     key: "com.android.os.statsd.key",
diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp
index f71d74f..f3a8989 100644
--- a/apex/statsd/service/Android.bp
+++ b/apex/statsd/service/Android.bp
@@ -1,5 +1,5 @@
 // Statsd Service jar, which will eventually be put in the statsd mainline apex.
-// service-statsd needs to be added to PRODUCT_SYSTEM_SERVER_JARS.
+// service-statsd needs to be added to PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS.
 // This jar will contain StatsCompanionService
 java_library {
     name: "service-statsd",
@@ -8,9 +8,9 @@
     srcs: [
         "java/**/*.java",
     ],
-
+    // TODO: link against the proper stubs (b/146084685).
     libs: [
-        "framework",
+        "framework-minus-apex",
         "services.core",
     ],
 }
diff --git a/api/current.txt b/api/current.txt
index 11ae3d5..2c1b066 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6732,6 +6732,7 @@
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
     method public boolean getAutoTime(@NonNull android.content.ComponentName);
     method @Deprecated public boolean getAutoTimeRequired();
+    method public boolean getAutoTimeZone(@NonNull android.content.ComponentName);
     method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
     method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
     method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
@@ -6850,6 +6851,7 @@
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTime(@NonNull android.content.ComponentName, boolean);
     method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
+    method public void setAutoTimeZone(@NonNull android.content.ComponentName, boolean);
     method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
@@ -25643,10 +25645,10 @@
   }
 
   public static interface MediaParser.OutputConsumer {
-    method public void onFormat(int, @NonNull android.media.MediaFormat);
     method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
     method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException, java.lang.InterruptedException;
     method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
+    method public void onTrackData(int, @NonNull android.media.MediaParser.TrackData);
     method public void onTracksFound(int);
   }
 
@@ -25667,6 +25669,11 @@
     method public void seekToPosition(long);
   }
 
+  public static final class MediaParser.TrackData {
+    field @Nullable public final android.media.DrmInitData drmInitData;
+    field @NonNull public final android.media.MediaFormat mediaFormat;
+  }
+
   public static final class MediaParser.UnrecognizedInputFormatException extends java.io.IOException {
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
old mode 100644
new mode 100755
index 4684690..b449b2e
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1305,6 +1305,7 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
     method public int getUsageSource();
+    method @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES) public void onCarrierPrivilegedAppsChanged();
     method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
@@ -1475,7 +1476,9 @@
   }
 
   public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getActiveDevices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public long getHiSyncId(@Nullable android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
   }
 
@@ -4377,6 +4380,7 @@
     method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
     method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
     method @Nullable public String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
+    method public void onHdmiDeviceUpdated(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
   }
 
   public abstract static class TvInputService.RecordingSession {
@@ -5668,7 +5672,6 @@
     method public boolean isApMacRandomizationSupported();
     method public boolean isConnectedMacRandomizationSupported();
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
-    method public boolean isDualBandSupported();
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean isDualModeSupported();
     method public boolean isPortableHotspotSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
@@ -5681,10 +5684,10 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
-    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSoftApBackupData(@NonNull byte[]);
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]);
     method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
-    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
@@ -6224,6 +6227,27 @@
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiState(int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiSupplicantStateChanged(int, boolean);
+    field public static final int WIFI_STATE_OFF = 0; // 0x0
+    field public static final int WIFI_STATE_OFF_SCANNING = 1; // 0x1
+    field public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; // 0x5
+    field public static final int WIFI_STATE_ON_CONNECTED_STA = 4; // 0x4
+    field public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6; // 0x6
+    field public static final int WIFI_STATE_ON_DISCONNECTED = 3; // 0x3
+    field public static final int WIFI_STATE_ON_NO_NETWORKS = 2; // 0x2
+    field public static final int WIFI_STATE_SOFT_AP = 7; // 0x7
+    field public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7; // 0x7
+    field public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6; // 0x6
+    field public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5; // 0x5
+    field public static final int WIFI_SUPPL_STATE_COMPLETED = 10; // 0xa
+    field public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1; // 0x1
+    field public static final int WIFI_SUPPL_STATE_DORMANT = 11; // 0xb
+    field public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8; // 0x8
+    field public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9; // 0x9
+    field public static final int WIFI_SUPPL_STATE_INACTIVE = 3; // 0x3
+    field public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2; // 0x2
+    field public static final int WIFI_SUPPL_STATE_INVALID = 0; // 0x0
+    field public static final int WIFI_SUPPL_STATE_SCANNING = 4; // 0x4
+    field public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12; // 0xc
   }
 
   public class Binder implements android.os.IBinder {
@@ -6615,6 +6639,21 @@
     field public static final int STATUS_WAITING_REBOOT = 5; // 0x5
   }
 
+  public class TelephonyServiceManager {
+    method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyServiceRegisterer();
+  }
+
+  public static class TelephonyServiceManager.ServiceNotFoundException extends java.lang.Exception {
+    ctor public TelephonyServiceManager.ServiceNotFoundException(@NonNull String);
+  }
+
+  public final class TelephonyServiceManager.ServiceRegisterer {
+    method @Nullable public android.os.IBinder get();
+    method @NonNull public android.os.IBinder getOrThrow() throws android.os.TelephonyServiceManager.ServiceNotFoundException;
+    method public void register(@NonNull android.os.IBinder);
+    method @Nullable public android.os.IBinder tryGet();
+  }
+
   public class UpdateEngine {
     ctor public UpdateEngine();
     method public void applyPayload(String, long, long, String[]);
@@ -9516,6 +9555,7 @@
   }
 
   public class SubscriptionInfo implements android.os.Parcelable {
+    method public boolean areUiccApplicationsEnabled();
     method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
     method public int getProfileClass();
     method public boolean isGroupDisabled();
@@ -9555,6 +9595,7 @@
 
   public class TelephonyFrameworkInitializer {
     method public static void registerServiceWrappers();
+    method public static void setTelephonyServiceManager(@NonNull android.os.TelephonyServiceManager);
   }
 
   public final class TelephonyHistogram implements android.os.Parcelable {
@@ -9656,6 +9697,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+    method public void requestModemActivityInfo(@NonNull android.os.ResultReceiver);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
@@ -9685,6 +9727,7 @@
     method public void updateServiceLocation();
     method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
+    field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
diff --git a/api/test-current.txt b/api/test-current.txt
index 00f66f1..7cfc218 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -722,6 +722,7 @@
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
     field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
     field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
+    field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
     field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
   }
 
@@ -753,6 +754,7 @@
     method public void setEnableRollback(boolean);
     method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+    method public void setInstallerPackageName(@Nullable String);
     method public void setRequestDowngrade(boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
@@ -4432,7 +4434,7 @@
     field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
     field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
     field public CharSequence accessibilityTitle;
-    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x400, equals=0x400, name="KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE_TRANSPARENT"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC")}) public int privateFlags;
+    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x400, equals=0x400, name="KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE_TRANSPARENT"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC"), @android.view.ViewDebug.FlagToString(mask=0x4000000, equals=0x4000000, name="FIT_INSETS_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x8000000, equals=0x8000000, name="ONLY_DRAW_BOTTOM_BAR_BACKGROUND")}) public int privateFlags;
   }
 
   public class WindowlessViewRoot {
diff --git a/cmds/hid/jni/Android.bp b/cmds/hid/jni/Android.bp
index 095cfc6..2c07de0 100644
--- a/cmds/hid/jni/Android.bp
+++ b/cmds/hid/jni/Android.bp
@@ -5,6 +5,7 @@
 
     shared_libs: [
         "libandroid",
+        "libbase",
         "liblog",
         "libnativehelper",
     ],
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index d4fdf85..f3871d7 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -21,10 +21,11 @@
 #include <linux/uhid.h>
 
 #include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
 #include <cstdio>
 #include <cstring>
 #include <memory>
-#include <unistd.h>
 
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
@@ -33,6 +34,8 @@
 #include <android/looper.h>
 #include <android/log.h>
 
+#include <android-base/stringprintf.h>
+
 #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
 #define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
 #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
@@ -61,6 +64,14 @@
     }
 }
 
+static std::string toString(const std::vector<uint8_t>& data) {
+    std::string s = "";
+    for (uint8_t b : data) {
+        s += android::base::StringPrintf("%x ", b);
+    }
+    return s;
+}
+
 DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
     mCallbackObject(env->NewGlobalRef(callback)) {
     env->GetJavaVM(&mJavaVM);
@@ -96,17 +107,17 @@
     return env;
 }
 
-Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
-        std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) {
-
+std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
+                                     const std::vector<uint8_t>& descriptor,
+                                     std::unique_ptr<DeviceCallback> callback) {
     size_t size = descriptor.size();
     if (size > HID_MAX_DESCRIPTOR_SIZE) {
         LOGE("Received invalid hid report with descriptor size %zu, skipping", size);
         return nullptr;
     }
 
-    int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
-    if (fd < 0) {
+    android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC));
+    if (!fd.ok()) {
         LOGE("Failed to open uhid: %s", strerror(errno));
         return nullptr;
     }
@@ -114,8 +125,7 @@
     struct uhid_event ev = {};
     ev.type = UHID_CREATE2;
     strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
-    memcpy(&ev.u.create2.rd_data, descriptor.data(),
-            size * sizeof(ev.u.create2.rd_data[0]));
+    memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0]));
     ev.u.create2.rd_size = size;
     ev.u.create2.bus = BUS_BLUETOOTH;
     ev.u.create2.vendor = vid;
@@ -126,7 +136,6 @@
     errno = 0;
     ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
     if (ret < 0 || ret != sizeof(ev)) {
-        ::close(fd);
         LOGE("Failed to create uhid node: %s", strerror(errno));
         return nullptr;
     }
@@ -134,21 +143,21 @@
     // Wait for the device to actually be created.
     ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
     if (ret < 0 || ev.type != UHID_START) {
-        ::close(fd);
         LOGE("uhid node failed to start: %s", strerror(errno));
         return nullptr;
     }
-    return new Device(id, fd, std::move(callback));
+    // using 'new' to access non-public constructor
+    return std::unique_ptr<Device>(new Device(id, std::move(fd), std::move(callback)));
 }
 
-Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
-            mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
+Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback)
+      : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) {
     ALooper* aLooper = ALooper_forThread();
     if (aLooper == NULL) {
         LOGE("Could not get ALooper, ALooper_forThread returned NULL");
         aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
     }
-    ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
+    ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
                   reinterpret_cast<void*>(this));
 }
 
@@ -162,8 +171,14 @@
     struct uhid_event ev = {};
     ev.type = UHID_DESTROY;
     TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
-    ::close(mFd);
-    mFd = -1;
+}
+
+// Send event over the fd.
+static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) {
+    ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
+    if (ret < 0 || ret != sizeof(ev)) {
+        LOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno));
+    }
 }
 
 void Device::sendReport(const std::vector<uint8_t>& report) const {
@@ -176,10 +191,7 @@
     ev.type = UHID_INPUT2;
     ev.u.input2.size = report.size();
     memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
-    ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
-    if (ret < 0 || ret != sizeof(ev)) {
-        LOGE("Failed to send hid event: %s", strerror(errno));
-    }
+    writeEvent(mFd, ev, "UHID_INPUT2");
 }
 
 void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const {
@@ -190,10 +202,7 @@
     ev.u.get_report_reply.size = report.size();
     memcpy(&ev.u.get_report_reply.data, report.data(),
             report.size() * sizeof(ev.u.get_report_reply.data[0]));
-    ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
-    if (ret < 0 || ret != sizeof(ev)) {
-        LOGE("Failed to send hid event (UHID_GET_REPORT_REPLY): %s", strerror(errno));
-    }
+    writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
 }
 
 int Device::handleEvents(int events) {
@@ -210,13 +219,31 @@
         return 0;
     }
 
-    if (ev.type == UHID_OPEN) {
-        mDeviceCallback->onDeviceOpen();
-    } else if (ev.type == UHID_GET_REPORT) {
-        mDeviceCallback->onDeviceGetReport(ev.u.get_report.id, ev.u.get_report.rnum);
-    } else if (ev.type == UHID_SET_REPORT) {
-        LOGE("UHID_SET_REPORT is currently not supported");
-        return 0;
+    switch (ev.type) {
+        case UHID_OPEN: {
+            mDeviceCallback->onDeviceOpen();
+            break;
+        }
+        case UHID_GET_REPORT: {
+            mDeviceCallback->onDeviceGetReport(ev.u.get_report.id, ev.u.get_report.rnum);
+            break;
+        }
+        case UHID_SET_REPORT: {
+            const struct uhid_set_report_req& set_report = ev.u.set_report;
+            if (set_report.size > UHID_DATA_MAX) {
+                LOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size);
+                return 0;
+            }
+
+            std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size);
+            LOGI("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
+                 set_report.rnum, toString(data).c_str());
+            break;
+        }
+        default: {
+            LOGI("Unhandled event type: %" PRIu32, ev.type);
+            break;
+        }
     }
 
     return 1;
@@ -250,9 +277,10 @@
 
     std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
 
-    uhid::Device* d = uhid::Device::open(
-            id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb));
-    return reinterpret_cast<jlong>(d);
+    std::unique_ptr<uhid::Device> d =
+            uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc,
+                               std::move(cb));
+    return reinterpret_cast<jlong>(d.release());
 }
 
 static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 892c7cd..b0471ed 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -19,6 +19,8 @@
 
 #include <jni.h>
 
+#include <android-base/unique_fd.h>
+
 namespace android {
 namespace uhid {
 
@@ -39,10 +41,10 @@
 
 class Device {
 public:
-    static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
-            std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback);
+    static std::unique_ptr<Device> open(int32_t id, const char* name, int32_t vid, int32_t pid,
+                                        const std::vector<uint8_t>& descriptor,
+                                        std::unique_ptr<DeviceCallback> callback);
 
-    Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
     ~Device();
 
     void sendReport(const std::vector<uint8_t>& report) const;
@@ -52,8 +54,9 @@
     int handleEvents(int events);
 
 private:
+    Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback);
     int32_t mId;
-    int mFd;
+    android::base::unique_fd mFd;
     std::unique_ptr<DeviceCallback> mDeviceCallback;
 };
 
diff --git a/cmds/media/Android.bp b/cmds/media/Android.bp
deleted file mode 100644
index 7879c53..0000000
--- a/cmds/media/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2013 The Android Open Source Project
-//
-
-java_binary {
-    name: "media",
-    wrapper: "media",
-    srcs: ["**/*.java"],
-}
diff --git a/cmds/media/MODULE_LICENSE_APACHE2 b/cmds/media/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/cmds/media/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/cmds/media/NOTICE b/cmds/media/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/cmds/media/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/cmds/media/media b/cmds/media/media
deleted file mode 100755
index 00c3915..0000000
--- a/cmds/media/media
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/system/bin/sh
-export CLASSPATH=/system/framework/media.jar
-exec app_process /system/bin com.android.commands.media.Media "$@"
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
index e07028bd..8aceb56 100644
--- a/core/java/android/annotation/OWNERS
+++ b/core/java/android/annotation/OWNERS
@@ -1,2 +1,3 @@
 tnorbye@google.com
+aurimas@google.com
 per-file UnsupportedAppUsage.java = mathewi@google.com, dbrazdil@google.com, atrost@google.com, andreionea@google.com
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index e96ff01..f589cc5 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -41,4 +41,29 @@
 @Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface SystemApi {
+    enum Client {
+        /**
+         * Specifies that the intended clients of a SystemApi are privileged apps.
+         * This is the default value for {@link #client}.
+         */
+        PRIVILEGED_APPS,
+    }
+
+    enum Process {
+        /**
+         * Specifies that the SystemAPI is available in every Java processes.
+         * This is the default value for {@link #process}.
+         */
+        ALL,
+    }
+
+    /**
+     * The intended client of this SystemAPI.
+     */
+    Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS;
+
+    /**
+     * The process(es) that this SystemAPI is available
+     */
+    Process process() default android.annotation.SystemApi.Process.ALL;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 93b6454..5cdc505 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -112,6 +112,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.TelephonyServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.permission.IPermissionManager;
@@ -128,6 +129,7 @@
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.system.StructStat;
+import android.telephony.TelephonyFrameworkInitializer;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
@@ -3415,7 +3417,7 @@
     private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
         final int displayId;
         try {
-            displayId = ActivityTaskManager.getService().getActivityDisplayId(r.token);
+            displayId = ActivityTaskManager.getService().getDisplayId(r.token);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4405,7 +4407,9 @@
                 r.newConfig = null;
             }
             if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
-            WindowManager.LayoutParams l = r.window.getAttributes();
+            ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
+            WindowManager.LayoutParams l = impl != null
+                    ? impl.mWindowAttributes : r.window.getAttributes();
             if ((l.softInputMode
                     & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                     != forwardBit) {
@@ -7432,6 +7436,9 @@
         final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
         TrustedCertificateStore.setDefaultUserDirectory(configDir);
 
+        // Call per-process mainline module initialization.
+        initializeMainlineModules();
+
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
@@ -7466,6 +7473,14 @@
         throw new RuntimeException("Main thread loop unexpectedly exited");
     }
 
+    /**
+     * Call various initializer APIs in mainline modules that need to be called when each process
+     * starts.
+     */
+    public static void initializeMainlineModules() {
+        TelephonyFrameworkInitializer.setTelephonyServiceManager(new TelephonyServiceManager());
+    }
+
     private void purgePendingResources() {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "purgePendingResources");
         nPurgePendingResources();
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 37136a1..e2b1b86 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -164,7 +164,7 @@
     boolean convertToTranslucent(in IBinder token, in Bundle options);
     void notifyActivityDrawn(in IBinder token);
     void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
-    int getActivityDisplayId(in IBinder activityToken);
+    int getDisplayId(in IBinder activityToken);
     boolean isImmersive(in IBinder token);
     void setImmersive(in IBinder token, boolean immersive);
     boolean isTopActivityImmersive();
@@ -405,6 +405,14 @@
     void setDisablePreviewScreenshots(IBinder token, boolean disable);
 
     /**
+     * It should only be called from home activity to remove its outdated snapshot. The home
+     * snapshot is used to speed up entering home from screen off. If the content of home activity
+     * is significantly different from before taking the snapshot, then the home activity can use
+     * this method to avoid inconsistent transition.
+     */
+    void invalidateHomeTaskSnapshot(IBinder homeToken);
+
+    /**
      * Return the user id of last resumed activity.
      */
     int getLastResumedActivityUserId();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index dd54d7c..bd948ec5 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -120,6 +120,7 @@
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
+import android.net.wifi.WifiCondManager;
 import android.net.wifi.WifiFrameworkInitializer;
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
@@ -696,6 +697,14 @@
                 return new EthernetManager(ctx.getOuterContext(), service);
             }});
 
+        registerService(Context.WIFI_COND_SERVICE, WifiCondManager.class,
+                new CachedServiceFetcher<WifiCondManager>() {
+                    @Override
+                    public WifiCondManager createService(ContextImpl ctx) {
+                        return new WifiCondManager(ctx.getOuterContext());
+                    }
+                });
+
         registerService(Context.WINDOW_SERVICE, WindowManager.class,
                 new CachedServiceFetcher<WindowManager>() {
             @Override
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 79d88fd..e5707bb 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -184,7 +184,7 @@
             return false;
         }
 
-        // Create a container surface to which the ActivityDisplay will be reparented
+        // Create a container surface to which the DisplayContent will be reparented
         final String name = "TaskEmbedder - " + Integer.toHexString(System.identityHashCode(this));
         mSurfaceControl = new SurfaceControl.Builder()
                 .setContainerLayer()
@@ -276,7 +276,7 @@
      * @see ActivityView.StateCallback
      * @see #startActivity(Intent)
      */
-    void setListener(TaskEmbedder.Listener listener) {
+    public void setListener(TaskEmbedder.Listener listener) {
         mListener = listener;
         if (mListener != null && isInitialized()) {
             mListener.onInitialized();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 63eb7ce..6e7ead1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2324,6 +2324,11 @@
 
     /**
      * Activity action: Starts the administrator to show policy compliance for the provisioning.
+     * This action is used any time that the administrator has an opportunity to show policy
+     * compliance before the end of setup wizard. This could happen as part of the admin-integrated
+     * provisioning flow (in which case this gets sent after {@link #ACTION_GET_PROVISIONING_MODE}),
+     * or it could happen during provisioning finalization if the administrator supports
+     * finalization during setup wizard.
      */
     public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
             "android.app.action.ADMIN_POLICY_COMPLIANCE";
@@ -5805,6 +5810,49 @@
     }
 
     /**
+     * Called by a device owner, a profile owner for the primary user or a profile
+     * owner of an organization-owned managed profile to turn auto time zone on and off.
+     * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
+     * to prevent the user from changing this setting.
+     * <p>
+     * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used,
+     * no user will be able set the date and time zone. Instead, the network date
+     * and time zone will be used.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param enabled Whether time zone should be obtained automatically from the network or not.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile.
+     */
+    public void setAutoTimeZone(@NonNull ComponentName admin, boolean enabled) {
+        throwIfParentInstance("setAutoTimeZone");
+        if (mService != null) {
+            try {
+                mService.setAutoTimeZone(admin, enabled);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * @return true if auto time zone is enabled on the device.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile.
+     */
+    public boolean getAutoTimeZone(@NonNull ComponentName admin) {
+        throwIfParentInstance("getAutoTimeZone");
+        if (mService != null) {
+            try {
+                return mService.getAutoTimeZone(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by a device owner to set whether all users created on the device should be ephemeral.
      * <p>
      * The system user is exempt from this policy - it is never ephemeral.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ff1ecd5..949e8ab 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -298,6 +298,9 @@
     void setAutoTime(in ComponentName who, boolean enabled);
     boolean getAutoTime(in ComponentName who);
 
+    void setAutoTimeZone(in ComponentName who, boolean enabled);
+    boolean getAutoTimeZone(in ComponentName who);
+
     void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
     boolean getForceEphemeralUsers(in ComponentName who);
 
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 099272d..4940976 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -597,6 +597,12 @@
     boolean isBackupServiceActive(int whichUser);
 
     /**
+    * Checks if the user is ready for backup or not.
+    * @param userId User id for which this operation should be performed.
+    */
+    boolean isUserReadyForBackup(int userId);
+
+    /**
      * Ask the framework which dataset, if any, the given package's data would be
      * restored from if we were to install it right now.
      *
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index fb5645a..419377c 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1125,8 +1125,11 @@
 
     /**
      * Inform usage stats that the carrier privileged apps access rules have changed.
+     * <p> The caller must have {@link android.Manifest.permission#BIND_CARRIER_SERVICES} </p>
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES)
     public void onCarrierPrivilegedAppsChanged() {
         try {
             mService.onCarrierPrivilegedAppsChanged();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3f8cb62..8404705 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -847,7 +847,8 @@
         }
         synchronized (mLock) {
             if (sBluetoothLeScanner == null) {
-                sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
+                sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(),
+                        getFeatureId());
             }
         }
         return sBluetoothLeScanner;
@@ -1637,6 +1638,15 @@
         return ActivityThread.currentOpPackageName();
     }
 
+    private String getFeatureId() {
+        // Workaround for legacy API for getting a BluetoothAdapter not
+        // passing a context
+        if (mContext != null) {
+            return mContext.getFeatureId();
+        }
+        return null;
+    }
+
     /**
      * Start the remote device discovery process.
      * <p>The discovery process usually involves an inquiry scan of about 12
@@ -1674,7 +1684,7 @@
         try {
             mServiceLock.readLock().lock();
             if (mService != null) {
-                return mService.startDiscovery(getOpPackageName());
+                return mService.startDiscovery(getOpPackageName(), getFeatureId());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index ead8429..b4521c6 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -335,9 +335,9 @@
      * is not active, it will be null on that position. Returns empty list on error.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public List<BluetoothDevice> getActiveDevices() {
+    public @NonNull List<BluetoothDevice> getActiveDevices() {
         if (VDBG) log("getActiveDevices()");
         final IBluetoothHearingAid service = getService();
         try {
@@ -559,8 +559,9 @@
      * @return the CustomerId of the device
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public long getHiSyncId(BluetoothDevice device) {
+    public long getHiSyncId(@Nullable BluetoothDevice device) {
         if (VDBG) {
             log("getCustomerId(" + device + ")");
         }
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index adedff3..7ff6466 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -22,7 +22,9 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -60,22 +62,34 @@
      * @hide
      */
     public BluetoothManager(Context context) {
-        context = context.getApplicationContext();
-        if (context == null) {
-            throw new IllegalArgumentException(
-                    "context not associated with any application (using a mock context?)");
+        if (context.getFeatureId() == null) {
+            context = context.getApplicationContext();
+            if (context == null) {
+                throw new IllegalArgumentException(
+                        "context not associated with any application (using a mock context?)");
+            }
+
+            mAdapter = BluetoothAdapter.getDefaultAdapter();
+        } else {
+            IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
+            if (b != null) {
+                mAdapter = new BluetoothAdapter(IBluetoothManager.Stub.asInterface(b));
+            } else {
+                Log.e(TAG, "Bluetooth binder is null");
+                mAdapter = null;
+            }
         }
-        // Legacy api - getDefaultAdapter does not take in the context
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        // Context is not initialized in constructor
         if (mAdapter != null) {
             mAdapter.setContext(context);
         }
     }
 
     /**
-     * Get the default BLUETOOTH Adapter for this device.
+     * Get the BLUETOOTH Adapter for this device.
      *
-     * @return the default BLUETOOTH Adapter
+     * @return the BLUETOOTH Adapter
      */
     public BluetoothAdapter getAdapter() {
         return mAdapter;
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index ac126ae..9a17346 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothGatt;
@@ -84,17 +83,25 @@
     private BluetoothAdapter mBluetoothAdapter;
     private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
 
+    private final String mOpPackageName;
+    private final String mFeatureId;
+
     /**
      * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
      *
      * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
+     * @param opPackageName The opPackageName of the context this object was created from
+     * @param featureId  The featureId of the context this object was created from
      * @hide
      */
-    public BluetoothLeScanner(IBluetoothManager bluetoothManager) {
+    public BluetoothLeScanner(IBluetoothManager bluetoothManager,
+            @NonNull String opPackageName, @Nullable String featureId) {
         mBluetoothManager = bluetoothManager;
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mHandler = new Handler(Looper.getMainLooper());
         mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
+        mOpPackageName = opPackageName;
+        mFeatureId = featureId;
     }
 
     /**
@@ -246,8 +253,8 @@
                 wrapper.startRegistration();
             } else {
                 try {
-                    gatt.startScanForIntent(callbackIntent, settings, filters,
-                            ActivityThread.currentOpPackageName());
+                    gatt.startScanForIntent(callbackIntent, settings, filters, mOpPackageName,
+                            mFeatureId);
                 } catch (RemoteException e) {
                     return ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
                 }
@@ -288,7 +295,7 @@
         IBluetoothGatt gatt;
         try {
             gatt = mBluetoothManager.getBluetoothGatt();
-            gatt.stopScanForIntent(callbackIntent, ActivityThread.currentOpPackageName());
+            gatt.stopScanForIntent(callbackIntent, mOpPackageName);
         } catch (RemoteException e) {
         }
     }
@@ -448,8 +455,7 @@
                         } else {
                             mScannerId = scannerId;
                             mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
-                                    mResultStorages,
-                                    ActivityThread.currentOpPackageName());
+                                    mResultStorages, mOpPackageName, mFeatureId);
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "fail to start le scan: " + e);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7b580c3..85027d9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3973,6 +3973,17 @@
     public static final String WIFI_SERVICE = "wifi";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.net.wifi.WifiCondManager} for handling management of the Wi-Fi control
+     * daemon.
+     *
+     * @see #getSystemService(String)
+     * @see android.net.wifi.WifiCondManager
+     * @hide
+     */
+    public static final String WIFI_COND_SERVICE = "wificond";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
      * Wi-Fi peer-to-peer connections.
@@ -4980,7 +4991,7 @@
      * {@link android.os.incremental.IncrementalManager}.
      * @hide
      */
-    public static final String INCREMENTAL_SERVICE = "incremental";
+    public static final String INCREMENTAL_SERVICE = "incremental_service";
 
     /**
      * Determine whether the given permission is allowed for a particular
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ca2de6a..47fb375 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1728,6 +1728,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final String EXTRA_ORIGINATING_UID
             = "android.intent.extra.ORIGINATING_UID";
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f017aad..8f51435 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1770,7 +1770,8 @@
          * @param installerPackageName name of the installer package
          * {@hide}
          */
-        public void setInstallerPackageName(String installerPackageName) {
+        @TestApi
+        public void setInstallerPackageName(@Nullable String installerPackageName) {
             this.installerPackageName = installerPackageName;
         }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6e890ba..94af541 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -946,7 +946,8 @@
             INSTALL_REASON_POLICY,
             INSTALL_REASON_DEVICE_RESTORE,
             INSTALL_REASON_DEVICE_SETUP,
-            INSTALL_REASON_USER
+            INSTALL_REASON_USER,
+            INSTALL_REASON_ROLLBACK
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InstallReason {}
@@ -977,6 +978,13 @@
     public static final int INSTALL_REASON_USER = 4;
 
     /**
+     * Code indicating that the package installation was a rollback initiated by RollbackManager.
+     *
+     * @hide
+     */
+    public static final int INSTALL_REASON_ROLLBACK = 5;
+
+    /**
      * @hide
      */
     public static final int INSTALL_UNKNOWN = 0;
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index edbf73a0..0deb2ab 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -2321,7 +2321,7 @@
                         parsingPackage.setProfileableByShell(true);
                     }
                     XmlUtils.skipCurrentTag(parser);
-
+                    break;
                 default:
                     if (!PackageParser.RIGID_PARSER) {
                         Slog.w(TAG, "Unknown element under <application>: " + tagName
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 5364313..fc210b2 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -768,6 +768,10 @@
         protected PatternMatcher[] uriPermissionPatterns;
         protected PathPermission[] pathPermissions;
 
+        public ParsedProvider(ParsedProvider other) {
+            this.setFrom(other);
+        }
+
         protected void setFrom(ParsedProvider other) {
             super.setFrom(other);
             this.exported = other.exported;
@@ -823,6 +827,10 @@
             return authority;
         }
 
+        public void setSyncable(boolean isSyncable) {
+            this.isSyncable = isSyncable;
+        }
+
         public boolean isSyncable() {
             return isSyncable;
         }
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
index af9ba8d..f2cf9a4 100644
--- a/core/java/android/content/pm/parsing/PackageInfoUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -485,6 +485,7 @@
                 pg.backgroundRequestDetailResourceId
         );
         assignSharedFieldsForPackageItemInfo(pgi, pg);
+        pgi.descriptionRes = pg.descriptionRes;
         pgi.priority = pg.priority;
         pgi.requestRes = pg.requestRes;
         pgi.flags = pg.flags;
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 8c2a65f..cda0e98 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -44,9 +44,10 @@
     // Used by the staging manager to notify the RollbackManager that a session is
     // being staged. In the case of multi-package sessions, the specified sessionId
     // is that of the parent session.
+    // Returns the rollback id if rollback was enabled successfully, or -1 if not.
     //
     // NOTE: This call is synchronous.
-    boolean notifyStagedSession(int sessionId);
+    int notifyStagedSession(int sessionId);
 
     // Used by the staging manager to notify the RollbackManager of the apk
     // session for a staged session.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 43842c5..156bcfe 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -21,6 +21,7 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -66,6 +67,7 @@
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
@@ -1019,6 +1021,16 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
+        mWindow.getWindow().setFitWindowInsetsTypes(WindowInsets.Type.systemBars());
+        mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND);
+        mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
+                (v, insets) -> v.onApplyWindowInsets(
+                        new WindowInsets.Builder(insets).setSystemWindowInsets(
+                                android.graphics.Insets.of(
+                                        insets.getSystemWindowInsetLeft(),
+                                        insets.getSystemWindowInsetTop(),
+                                        insets.getSystemWindowInsetRight(),
+                                        insets.getStableInsetBottom())).build()));
         // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
         // by default (but IME developers can opt this out later if they want a new behavior).
         mWindow.getWindow().setFlags(
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4754444..53ea936 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -17,6 +17,8 @@
 package android.os;
 
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
+import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
 
 import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
@@ -24,6 +26,8 @@
 import android.app.job.JobParameters;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.os.BatteryStatsManager.WifiState;
+import android.os.BatteryStatsManager.WifiSupplState;
 import android.server.ServerProtoEnums;
 import android.service.batterystats.BatteryStatsServiceDumpHistoryProto;
 import android.service.batterystats.BatteryStatsServiceDumpProto;
@@ -2458,41 +2462,6 @@
      */
     public abstract Timer getPhoneDataConnectionTimer(int dataType);
 
-    public static final int WIFI_SUPPL_STATE_INVALID = 0;
-    public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1;
-    public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2;
-    public static final int WIFI_SUPPL_STATE_INACTIVE = 3;
-    public static final int WIFI_SUPPL_STATE_SCANNING = 4;
-    public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5;
-    public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6;
-    public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7;
-    public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8;
-    public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9;
-    public static final int WIFI_SUPPL_STATE_COMPLETED = 10;
-    public static final int WIFI_SUPPL_STATE_DORMANT = 11;
-    public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12;
-
-    public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED+1;
-
-    /** @hide */
-    @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
-            WIFI_SUPPL_STATE_INVALID,
-            WIFI_SUPPL_STATE_DISCONNECTED,
-            WIFI_SUPPL_STATE_INTERFACE_DISABLED,
-            WIFI_SUPPL_STATE_INACTIVE,
-            WIFI_SUPPL_STATE_SCANNING,
-            WIFI_SUPPL_STATE_AUTHENTICATING,
-            WIFI_SUPPL_STATE_ASSOCIATING,
-            WIFI_SUPPL_STATE_ASSOCIATED,
-            WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE,
-            WIFI_SUPPL_STATE_GROUP_HANDSHAKE,
-            WIFI_SUPPL_STATE_COMPLETED,
-            WIFI_SUPPL_STATE_DORMANT,
-            WIFI_SUPPL_STATE_UNINITIALIZED,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface WifiSupplState {}
-
     static final String[] WIFI_SUPPL_STATE_NAMES = {
         "invalid", "disconn", "disabled", "inactive", "scanning",
         "authenticating", "associating", "associated", "4-way-handshake",
@@ -2635,31 +2604,6 @@
     @UnsupportedAppUsage
     public abstract long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which);
 
-    public static final int WIFI_STATE_OFF = 0;
-    public static final int WIFI_STATE_OFF_SCANNING = 1;
-    public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
-    public static final int WIFI_STATE_ON_DISCONNECTED = 3;
-    public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
-    public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
-    public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
-    public static final int WIFI_STATE_SOFT_AP = 7;
-
-    public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
-
-    /** @hide */
-    @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
-            WIFI_STATE_OFF,
-            WIFI_STATE_OFF_SCANNING,
-            WIFI_STATE_ON_NO_NETWORKS,
-            WIFI_STATE_ON_DISCONNECTED,
-            WIFI_STATE_ON_CONNECTED_STA,
-            WIFI_STATE_ON_CONNECTED_P2P,
-            WIFI_STATE_ON_CONNECTED_STA_P2P,
-            WIFI_STATE_SOFT_AP
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface WifiState {}
-
     static final String[] WIFI_STATE_NAMES = {
         "off", "scanning", "no_net", "disconn",
         "sta", "p2p", "sta_p2p", "soft_ap"
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index e5650ae..0545666 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,6 +29,9 @@
 
 import com.android.internal.app.IBatteryStats;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This class provides an API surface for internal system components to report events that are
  * needed for battery usage/estimation and battery blaming for apps.
@@ -39,6 +43,116 @@
 @SystemApi
 @SystemService(Context.BATTERY_STATS_SERVICE)
 public class BatteryStatsManager {
+    /**
+     * Wifi states.
+     *
+     * @see #noteWifiState(int, String)
+     */
+    /**
+     * Wifi fully off.
+     */
+    public static final int WIFI_STATE_OFF = 0;
+    /**
+     * Wifi connectivity off, but scanning enabled.
+     */
+    public static final int WIFI_STATE_OFF_SCANNING = 1;
+    /**
+     * Wifi on, but no saved infrastructure networks to connect to.
+     */
+    public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
+    /**
+     * Wifi on, but not connected to any infrastructure networks.
+     */
+    public static final int WIFI_STATE_ON_DISCONNECTED = 3;
+    /**
+     * Wifi on and connected to a infrastructure network.
+     */
+    public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
+    /**
+     * Wifi on and connected to a P2P device, but no infrastructure connection to a network.
+     */
+    public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
+    /**
+     * Wifi on and connected to both a P2P device and infrastructure connection to a network.
+     */
+    public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
+    /**
+     * SoftAp/Hotspot turned on.
+     */
+    public static final int WIFI_STATE_SOFT_AP = 7;
+
+    /** @hide */
+    public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
+            WIFI_STATE_OFF,
+            WIFI_STATE_OFF_SCANNING,
+            WIFI_STATE_ON_NO_NETWORKS,
+            WIFI_STATE_ON_DISCONNECTED,
+            WIFI_STATE_ON_CONNECTED_STA,
+            WIFI_STATE_ON_CONNECTED_P2P,
+            WIFI_STATE_ON_CONNECTED_STA_P2P,
+            WIFI_STATE_SOFT_AP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiState {}
+
+    /**
+     * Wifi supplicant daemon states.
+     *
+     * @see android.net.wifi.SupplicantState for detailed description of states.
+     * @see #noteWifiSupplicantStateChanged(int)
+     */
+    /** @see android.net.wifi.SupplicantState#INVALID */
+    public static final int WIFI_SUPPL_STATE_INVALID = 0;
+    /** @see android.net.wifi.SupplicantState#DISCONNECTED*/
+    public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1;
+    /** @see android.net.wifi.SupplicantState#INTERFACE_DISABLED */
+    public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2;
+    /** @see android.net.wifi.SupplicantState#INACTIVE*/
+    public static final int WIFI_SUPPL_STATE_INACTIVE = 3;
+    /** @see android.net.wifi.SupplicantState#SCANNING*/
+    public static final int WIFI_SUPPL_STATE_SCANNING = 4;
+    /** @see android.net.wifi.SupplicantState#AUTHENTICATING */
+    public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5;
+    /** @see android.net.wifi.SupplicantState#ASSOCIATING */
+    public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6;
+    /** @see android.net.wifi.SupplicantState#ASSOCIATED */
+    public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7;
+    /** @see android.net.wifi.SupplicantState#FOUR_WAY_HANDSHAKE */
+    public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8;
+    /** @see android.net.wifi.SupplicantState#GROUP_HANDSHAKE */
+    public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9;
+    /** @see android.net.wifi.SupplicantState#COMPLETED */
+    public static final int WIFI_SUPPL_STATE_COMPLETED = 10;
+    /** @see android.net.wifi.SupplicantState#DORMANT */
+    public static final int WIFI_SUPPL_STATE_DORMANT = 11;
+    /** @see android.net.wifi.SupplicantState#UNINITIALIZED */
+    public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12;
+
+    /** @hide */
+    public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED + 1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
+            WIFI_SUPPL_STATE_INVALID,
+            WIFI_SUPPL_STATE_DISCONNECTED,
+            WIFI_SUPPL_STATE_INTERFACE_DISABLED,
+            WIFI_SUPPL_STATE_INACTIVE,
+            WIFI_SUPPL_STATE_SCANNING,
+            WIFI_SUPPL_STATE_AUTHENTICATING,
+            WIFI_SUPPL_STATE_ASSOCIATING,
+            WIFI_SUPPL_STATE_ASSOCIATED,
+            WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE,
+            WIFI_SUPPL_STATE_GROUP_HANDSHAKE,
+            WIFI_SUPPL_STATE_COMPLETED,
+            WIFI_SUPPL_STATE_DORMANT,
+            WIFI_SUPPL_STATE_UNINITIALIZED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiSupplState {}
+
     private final IBatteryStats mBatteryStats;
 
     /** @hide */
@@ -91,7 +205,7 @@
      * @param accessPoint SSID of the network if wifi is connected to STA, else null.
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void noteWifiState(@BatteryStats.WifiState int newWifiState,
+    public void noteWifiState(@WifiState int newWifiState,
             @Nullable String accessPoint) {
         try {
             mBatteryStats.noteWifiState(newWifiState, accessPoint);
@@ -224,7 +338,7 @@
      *                   authentication failure.
      */
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
-    public void noteWifiSupplicantStateChanged(@BatteryStats.WifiSupplState int newSupplState,
+    public void noteWifiSupplicantStateChanged(@WifiSupplState int newSupplState,
             boolean failedAuth) {
         try {
             mBatteryStats.noteWifiSupplicantStateChanged(newSupplState, failedAuth);
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index ee95fce..b0c2546 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -479,8 +479,14 @@
             // For now, avoid spamming the log by disabling after we've logged
             // about this interface at least once
             mWarnOnBlocking = false;
-            Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
-                    new Throwable());
+            if (Build.IS_USERDEBUG) {
+                // Log this as a WTF on userdebug builds.
+                Log.wtf(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+                        new Throwable());
+            } else {
+                Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+                        new Throwable());
+            }
         }
 
         final boolean tracingEnabled = Binder.isTracingEnabled();
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index bf9225a..3c0997b 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -140,7 +140,7 @@
 
     /**
      * Returns a reference to a service with the given name, or throws
-     * {@link NullPointerException} if none is found.
+     * {@link ServiceNotFoundException} if none is found.
      *
      * @hide
      */
diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java
new file mode 100644
index 0000000..1211dd6
--- /dev/null
+++ b/core/java/android/os/TelephonyServiceManager.java
@@ -0,0 +1,138 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+/**
+ * Provides a way to register and obtain the system service binder objects managed by the telephony
+ * service.
+ *
+ * <p>Only the telephony mainline module will be able to access an instance of this class.
+ *
+ * @hide
+ */
+@SystemApi
+public class TelephonyServiceManager {
+    /**
+     * @hide
+     */
+    public TelephonyServiceManager() {
+    }
+
+    /**
+     * A class that exposes the methods to register and obtain each system service.
+     */
+    public final class ServiceRegisterer {
+        private final String mServiceName;
+
+        /**
+         * @hide
+         */
+        public ServiceRegisterer(String serviceName) {
+            mServiceName = serviceName;
+        }
+
+        /**
+         * Register a system server binding object for a service.
+         */
+        public void register(@NonNull IBinder binder) {
+            ServiceManager.addService(mServiceName, binder);
+        }
+
+        /**
+         * Get the system server binding object for a service.
+         *
+         * <p>This blocks until the service instance is ready,
+         * or a timeout happens, in which case it returns null.
+         */
+        @Nullable
+        public IBinder get() {
+            return ServiceManager.getService(mServiceName);
+        }
+
+        /**
+         * Get the system server binding object for a service.
+         *
+         * <p>This blocks until the service instance is ready,
+         * or a timeout happens, in which case it throws {@link ServiceNotFoundException}.
+         */
+        @NonNull
+        public IBinder getOrThrow() throws ServiceNotFoundException {
+            try {
+                return ServiceManager.getServiceOrThrow(mServiceName);
+            } catch (ServiceManager.ServiceNotFoundException e) {
+                throw new ServiceNotFoundException(mServiceName);
+            }
+        }
+
+        /**
+         * Get the system server binding object for a service. If the specified service is
+         * not available, it returns null.
+         */
+        @Nullable
+        public IBinder tryGet() {
+            return ServiceManager.checkService(mServiceName);
+        }
+    }
+
+    /**
+     * See {@link ServiceRegisterer#getOrThrow}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException {
+        /**
+         * Constructor.
+         *
+         * @param name the name of the binder service that cannot be found.
+         *
+         */
+        public ServiceNotFoundException(@NonNull String name) {
+            super(name);
+        }
+    }
+
+    /**
+     * Returns {@link ServiceRegisterer} for the "telephony" service.
+     */
+    @NonNull
+    public ServiceRegisterer getTelephonyServiceRegisterer() {
+        return new ServiceRegisterer("phone");
+    }
+
+
+// TODO: Add more services...
+//
+//    /**
+//     * Returns {@link ServiceRegisterer} for the "subscription" service.
+//     */
+//    @NonNull
+//    public ServiceRegisterer getSubscriptionServiceRegisterer() {
+//        return new ServiceRegisterer("isub");
+//    }
+//
+//    /**
+//     * Returns {@link ServiceRegisterer} for the "SMS" service.
+//     */
+//    @NonNull
+//    public ServiceRegisterer getSmsServiceRegisterer() {
+//        return new ServiceRegisterer("isms");
+//    }
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 137f537..d099629 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2391,19 +2391,11 @@
      */
     public @Nullable UserInfo createUser(@Nullable String name, @NonNull String userType,
             @UserInfoFlag int flags) {
-        UserInfo user = null;
         try {
-            user = mService.createUser(name, userType, flags);
-            // TODO: Keep this in sync with
-            // UserManagerService.LocalService.createUserEvenWhenDisallowed
-            if (user != null && !user.isAdmin() && !user.isDemo()) {
-                mService.setUserRestriction(DISALLOW_SMS, true, user.id);
-                mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
-            }
+            return mService.createUser(name, userType, flags);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
-        return user;
     }
 
     /**
@@ -2748,8 +2740,7 @@
     /**
      * Assigns admin privileges to the user, if such a user exists.
      *
-     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} and
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
+     * <p>Note that this does not alter the user's pre-existing user restrictions.
      *
      * @param userId the id of the user to become admin
      * @hide
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index e9b3837..895d837 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -46,9 +47,9 @@
     private long mEnergyConsumedMaMillis = 0;
     private long mNumAppScanRequest = 0;
     private long[] mTimeInStateMillis =
-        new long[BatteryStats.NUM_WIFI_STATES];
+        new long[BatteryStatsManager.NUM_WIFI_STATES];
     private long[] mTimeInSupplicantStateMillis =
-        new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
+        new long[BatteryStatsManager.NUM_WIFI_SUPPL_STATES];
     private long[] mTimeInRxSignalStrengthLevelMillis =
         new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
     private long mMonitoredRailChargeConsumedMaMillis = 0;
@@ -369,7 +370,7 @@
     /** @hide */
     public void setTimeInStateMillis(long[] t) {
         mTimeInStateMillis = Arrays.copyOfRange(t, 0,
-                Math.min(t.length, BatteryStats.NUM_WIFI_STATES));
+                Math.min(t.length, BatteryStatsManager.NUM_WIFI_STATES));
         return;
     }
 
@@ -383,7 +384,7 @@
     /** @hide */
     public void setTimeInSupplicantStateMillis(long[] t) {
         mTimeInSupplicantStateMillis = Arrays.copyOfRange(
-                t, 0, Math.min(t.length, BatteryStats.NUM_WIFI_SUPPL_STATES));
+                t, 0, Math.min(t.length, BatteryStatsManager.NUM_WIFI_SUPPL_STATES));
         return;
     }
 
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index d6446d4..f84d7ef 100644
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -16,89 +16,22 @@
 
 package android.os.incremental;
 
+import android.os.incremental.IncrementalFileSystemControlParcel;
 import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.content.pm.IDataLoaderStatusListener;
 
-/** @hide */
+/**
+ * Binder service to receive calls from native Incremental Service and handle Java tasks such as
+ * looking up data loader service package names, binding and talking to the data loader service.
+ * @hide
+ */
 interface IIncrementalManager {
-    /**
-     * A set of flags for the |createMode| parameters when creating a new Incremental storage.
-     */
-    const int CREATE_MODE_TEMPORARY_BIND = 1;
-    const int CREATE_MODE_PERMANENT_BIND = 2;
-    const int CREATE_MODE_CREATE = 4;
-    const int CREATE_MODE_OPEN_EXISTING = 8;
-
-    /**
-     * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
-     */
-    int openStorage(in @utf8InCpp String path);
-    int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
-    int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
-
-    /**
-     * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
-     */
-    const int BIND_TEMPORARY = 0;
-    const int BIND_PERMANENT = 1;
-    int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
-
-    /**
-     * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
-     */
-    int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
-
-    /**
-     * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
-     */
-    int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
-     * All the parent directories of the target directory will be created if they do not exist already.
-     */
-    int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Creates a file under a storage, specifying its name, size and metadata.
-     */
-    int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
-
-    /**
-     * Creates a file under a storage. Content of the file is from a range inside another file.
-     * Both files are specified by relative paths under storage.
-     */
-    int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
-
-    /**
-     * Creates a hard link between two files in two storage instances.
-     * Source and dest specified by parent storage IDs and their relative paths under the storage.
-     * The source and dest storage instances should be in the same fs mount.
-     * Note: destStorageId can be the same as sourceStorageId.
-     */
-    int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
-
-    /**
-     * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
-     */
-    int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
-     */
-    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
-
-    /**
-     * Reads the metadata of a file. File is specified by relative path under storage.
-     */
-    byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Starts loading data for a storage.
-     */
-    boolean startLoading(int storageId);
-
-    /**
-     * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
-     */
-    void deleteStorage(int storageId);
+    boolean prepareDataLoader(int mountId,
+        in IncrementalFileSystemControlParcel control,
+        in IncrementalDataLoaderParamsParcel params,
+        in IDataLoaderStatusListener listener);
+    boolean startDataLoader(int mountId);
+    void showHealthBlockedUI(int mountId);
+    void destroyDataLoader(int mountId);
+    void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
 }
diff --git a/core/java/android/os/incremental/IIncrementalManagerNative.aidl b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
new file mode 100644
index 0000000..d9c7c6b
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
@@ -0,0 +1,104 @@
+/*
+ * 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.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+
+/** @hide */
+interface IIncrementalManagerNative {
+    /**
+     * A set of flags for the |createMode| parameters when creating a new Incremental storage.
+     */
+    const int CREATE_MODE_TEMPORARY_BIND = 1;
+    const int CREATE_MODE_PERMANENT_BIND = 2;
+    const int CREATE_MODE_CREATE = 4;
+    const int CREATE_MODE_OPEN_EXISTING = 8;
+
+    /**
+     * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
+     */
+    int openStorage(in @utf8InCpp String path);
+    int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
+    int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
+
+    /**
+     * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
+     */
+    const int BIND_TEMPORARY = 0;
+    const int BIND_PERMANENT = 1;
+    int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
+
+    /**
+     * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
+     */
+    int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
+
+    /**
+     * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     */
+    int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     * All the parent directories of the target directory will be created if they do not exist already.
+     */
+    int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Creates a file under a storage, specifying its name, size and metadata.
+     */
+    int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
+
+    /**
+     * Creates a file under a storage. Content of the file is from a range inside another file.
+     * Both files are specified by relative paths under storage.
+     */
+    int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
+
+    /**
+     * Creates a hard link between two files in two storage instances.
+     * Source and dest specified by parent storage IDs and their relative paths under the storage.
+     * The source and dest storage instances should be in the same fs mount.
+     * Note: destStorageId can be the same as sourceStorageId.
+     */
+    int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
+
+    /**
+     * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
+     */
+    int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
+     */
+    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
+
+    /**
+     * Reads the metadata of a file. File is specified by relative path under storage.
+     */
+    byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Starts loading data for a storage.
+     */
+    boolean startLoading(int storageId);
+
+    /**
+     * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
+     */
+    void deleteStorage(int storageId);
+}
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
deleted file mode 100644
index ffff52e..0000000
--- a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.incremental;
-
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.content.pm.IDataLoaderStatusListener;
-
-/**
- * Binder service to receive calls from native Incremental Service and handle Java tasks such as
- * looking up data loader service package names, binding and talking to the data loader service.
- * @hide
- */
-interface IIncrementalServiceProxy {
-    boolean prepareDataLoader(int mountId,
-        in IncrementalFileSystemControlParcel control,
-        in IncrementalDataLoaderParamsParcel params,
-        in IDataLoaderStatusListener listener);
-    boolean startDataLoader(int mountId);
-    void showHealthBlockedUI(int mountId);
-    void destroyDataLoader(int mountId);
-    void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
-}
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 5aabf86..c30f558 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -36,31 +36,28 @@
 import java.nio.file.Paths;
 
 /**
- * Provides operations to open or create an IncrementalStorage, using IIncrementalManager service.
- * Example Usage:
+ * Provides operations to open or create an IncrementalStorage, using IIncrementalManagerNative
+ * service. Example Usage:
  *
  * <blockquote><pre>
- * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_SERVICE);
  * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
  * </pre></blockquote>
  *
  * @hide
  */
 @SystemService(Context.INCREMENTAL_SERVICE)
-public class IncrementalManager {
+public final class IncrementalManager {
     private static final String TAG = "IncrementalManager";
-    private final IIncrementalManager mService;
-    @GuardedBy("mStorages")
-    private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
 
     public static final int CREATE_MODE_TEMPORARY_BIND =
-            IIncrementalManager.CREATE_MODE_TEMPORARY_BIND;
+            IIncrementalManagerNative.CREATE_MODE_TEMPORARY_BIND;
     public static final int CREATE_MODE_PERMANENT_BIND =
-            IIncrementalManager.CREATE_MODE_PERMANENT_BIND;
+            IIncrementalManagerNative.CREATE_MODE_PERMANENT_BIND;
     public static final int CREATE_MODE_CREATE =
-            IIncrementalManager.CREATE_MODE_CREATE;
+            IIncrementalManagerNative.CREATE_MODE_CREATE;
     public static final int CREATE_MODE_OPEN_EXISTING =
-            IIncrementalManager.CREATE_MODE_OPEN_EXISTING;
+            IIncrementalManagerNative.CREATE_MODE_OPEN_EXISTING;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"CREATE_MODE_"}, value = {
@@ -72,8 +69,12 @@
     public @interface CreateMode {
     }
 
-    public IncrementalManager(@NonNull IIncrementalManager is) {
-        mService = is;
+    private final @Nullable IIncrementalManagerNative mNativeService;
+    @GuardedBy("mStorages")
+    private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
+
+    public IncrementalManager(IIncrementalManagerNative nativeService) {
+        mNativeService = nativeService;
     }
 
     /**
@@ -82,6 +83,7 @@
      * @param storageId The storage ID to identify the storage object.
      * @return IncrementalStorage object corresponding to storage ID.
      */
+    // TODO(b/136132412): remove this
     @Nullable
     public IncrementalStorage getStorage(int storageId) {
         synchronized (mStorages) {
@@ -95,8 +97,8 @@
      *
      * @param path                Absolute path to mount Incremental File System on.
      * @param params              IncrementalDataLoaderParams object to configure data loading.
-     * @param createMode          Mode for opening an old Incremental File System mount or
-     *                            creating a new mount.
+     * @param createMode          Mode for opening an old Incremental File System mount or creating
+     *                            a new mount.
      * @param autoStartDataLoader Set true to immediately start data loader after creating storage.
      * @return IncrementalStorage object corresponding to the mounted directory.
      */
@@ -105,11 +107,11 @@
             @NonNull IncrementalDataLoaderParams params, @CreateMode int createMode,
             boolean autoStartDataLoader) {
         try {
-            final int id = mService.createStorage(path, params.getData(), createMode);
+            final int id = mNativeService.createStorage(path, params.getData(), createMode);
             if (id < 0) {
                 return null;
             }
-            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
             synchronized (mStorages) {
                 mStorages.put(id, storage);
             }
@@ -123,8 +125,8 @@
     }
 
     /**
-     * Opens an existing Incremental File System mounted directory and returns an
-     * IncrementalStorage object.
+     * Opens an existing Incremental File System mounted directory and returns an IncrementalStorage
+     * object.
      *
      * @param path Absolute target path that Incremental File System has been mounted on.
      * @return IncrementalStorage object corresponding to the mounted directory.
@@ -132,11 +134,11 @@
     @Nullable
     public IncrementalStorage openStorage(@NonNull String path) {
         try {
-            final int id = mService.openStorage(path);
+            final int id = mNativeService.openStorage(path);
             if (id < 0) {
                 return null;
             }
-            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
             synchronized (mStorages) {
                 mStorages.put(id, storage);
             }
@@ -155,11 +157,12 @@
     public IncrementalStorage createStorage(@NonNull String path,
             @NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) {
         try {
-            final int id = mService.createLinkedStorage(path, linkedStorage.getId(), createMode);
+            final int id = mNativeService.createLinkedStorage(
+                    path, linkedStorage.getId(), createMode);
             if (id < 0) {
                 return null;
             }
-            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            final IncrementalStorage storage = new IncrementalStorage(mNativeService, id);
             synchronized (mStorages) {
                 mStorages.put(id, storage);
             }
@@ -175,6 +178,7 @@
      * @param file Target file to search storage for.
      * @return Absolute path which is a bind-mount point of Incremental File System.
      */
+    @Nullable
     private Path getStoragePathForFile(File file) {
         File currentPath = new File(file.getParent());
         while (currentPath.getParent() != null) {
@@ -198,18 +202,19 @@
      *     </li>
      * </ol>
      *
-     * @param sourcePath   Absolute path to the source. Should be the same type as the destPath
-     *                     (file or dir). Expected to already exist and is an Incremental path.
-     * @param destPath     Absolute path to the destination.
-     * @throws IllegalArgumentException when 1) source does not exist,
-     *                     or 2) source and dest type mismatch (one is file and the other is dir),
-     *                     or 3) source path is not on Incremental File System,
-     * @throws IOException when 1) cannot find the root path of the Incremental storage of source,
-     *                     or 2) cannot retrieve the Incremental storage instance of the source,
-     *                     or 3) renaming a file, but dest is not on the same Incremental Storage,
-     *                     or 4) renaming a dir, dest dir does not exist but fails to be created.
-     *
-     * TODO(b/136132412): add unit tests
+     * @param sourcePath Absolute path to the source. Should be the same type as the destPath (file
+     *                   or dir). Expected to already exist and is an Incremental path.
+     * @param destPath   Absolute path to the destination.
+     * @throws IllegalArgumentException when 1) source does not exist, or 2) source and dest type
+     *                                  mismatch (one is file and the other is dir), or 3) source
+     *                                  path is not on Incremental File System,
+     * @throws IOException              when 1) cannot find the root path of the Incremental storage
+     *                                  of source, or 2) cannot retrieve the Incremental storage
+     *                                  instance of the source, or 3) renaming a file, but dest is
+     *                                  not on the same Incremental Storage, or 4) renaming a dir,
+     *                                  dest dir does not exist but fails to be created.
+     *                                  <p>
+     *                                  TODO(b/136132412): add unit tests
      */
     public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
         final File source = new File(sourcePath);
@@ -243,6 +248,7 @@
         if (storage == null) {
             throw new IOException("Failed to retrieve storage from Incremental Service.");
         }
+
         if (source.isFile()) {
             renameFile(storage, storagePath, source, dest);
         } else {
@@ -304,11 +310,11 @@
      */
     public void closeStorage(@NonNull String path) {
         try {
-            final int id = mService.openStorage(path);
+            final int id = mNativeService.openStorage(path);
             if (id < 0) {
                 return;
             }
-            mService.deleteStorage(id);
+            mNativeService.deleteStorage(id);
             synchronized (mStorages) {
                 mStorages.remove(id);
             }
@@ -321,7 +327,7 @@
      * Checks if path is mounted on Incremental File System.
      */
     public static boolean isIncrementalPath(@NonNull String path) {
-        // TODO(b/136132412): implement native method
+        // TODO(b/136132412): add jni implementation
         return false;
     }
 }
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 2bf89ed..2750868 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -24,11 +24,11 @@
 import java.io.IOException;
 
 /**
- * Provides operations on an Incremental File System directory, using IncrementalService. Example
- * usage:
+ * Provides operations on an Incremental File System directory, using IncrementalServiceNative.
+ * Example usage:
  *
  * <blockquote><pre>
- * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_SERVICE);
  * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
  * storage.makeDirectory("subdir");
  * </pre></blockquote>
@@ -38,10 +38,10 @@
 public final class IncrementalStorage {
     private static final String TAG = "IncrementalStorage";
     private final int mId;
-    private final IIncrementalManager mService;
+    private final IIncrementalManagerNative mService;
 
 
-    public IncrementalStorage(@NonNull IIncrementalManager is, int id) {
+    public IncrementalStorage(@NonNull IIncrementalManagerNative is, int id) {
         mService = is;
         mId = id;
     }
@@ -72,7 +72,7 @@
             throws IOException {
         try {
             int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
-                    IIncrementalManager.BIND_TEMPORARY);
+                    IIncrementalManagerNative.BIND_TEMPORARY);
             if (res < 0) {
                 throw new IOException("bind() failed with errno " + -res);
             }
@@ -103,7 +103,7 @@
             throws IOException {
         try {
             int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
-                    IIncrementalManager.BIND_PERMANENT);
+                    IIncrementalManagerNative.BIND_PERMANENT);
             if (res < 0) {
                 throw new IOException("bind() permanent failed with errno " + -res);
             }
@@ -274,7 +274,8 @@
             throw new IOException("moveDir() requires that destination dir already exists.");
         }
         try {
-            int res = mService.makeBindMount(mId, "", destPath, IIncrementalManager.BIND_PERMANENT);
+            int res = mService.makeBindMount(mId, "", destPath,
+                    IIncrementalManagerNative.BIND_PERMANENT);
             if (res < 0) {
                 throw new IOException("moveDir() failed at making bind mount, errno " + -res);
             }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2d70986d..62603fe 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -80,6 +80,7 @@
 import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -156,7 +157,8 @@
     /** {@hide} */
     public static final String PROP_FUSE = "persist.sys.fuse";
     /** {@hide} */
-    public static final String PROP_FUSE_SNAPSHOT = "sys.fuse_snapshot";
+    public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
+            + FeatureFlagUtils.SETTINGS_FUSE_FLAG;
 
 
     /** {@hide} */
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8bf723f..eb1684f 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2916,6 +2916,8 @@
          */
         @Nullable
         public static String getLocalAccountName(@NonNull Context context) {
+            //  config_rawContactsLocalAccountName is defined in
+            //  platform/frameworks/base/core/res/res/values/config.xml
             return TextUtils.nullIfEmpty(context.getString(
                     com.android.internal.R.string.config_rawContactsLocalAccountName));
         }
@@ -2933,6 +2935,8 @@
          */
         @Nullable
         public static String getLocalAccountType(@NonNull Context context) {
+            //  config_rawContactsLocalAccountType is defined in
+            //  platform/frameworks/base/core/res/res/values/config.xml
             return TextUtils.nullIfEmpty(context.getString(
                     com.android.internal.R.string.config_rawContactsLocalAccountType));
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 165c284..197d814 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8410,6 +8410,12 @@
         public static final String TAP_GESTURE = "tap_gesture";
 
         /**
+         * Controls whether the people strip is enabled.
+         * @hide
+         */
+        public static final String PEOPLE_STRIP = "people_strip";
+
+        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -10312,6 +10318,19 @@
         public static final String ERROR_LOGCAT_PREFIX = "logcat_for_";
 
         /**
+         * Maximum number of bytes of a system crash/ANR/etc. report that
+         * ActivityManagerService should send to DropBox, as a prefix of the
+         * dropbox tag of the report type. For example,
+         * "max_error_bytes_for_system_server_anr" controls the maximum
+         * number of bytes captured with system server ANR reports.
+         * <p>
+         * Type: int (max size in bytes)
+         *
+         * @hide
+         */
+        public static final String MAX_ERROR_BYTES_PREFIX = "max_error_bytes_for_";
+
+        /**
          * The interval in minutes after which the amount of free storage left
          * on the device is logged to the event log
          *
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f6da01b..c287ae3 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1308,8 +1308,7 @@
              * Broadcast action: When SMS-MMS db is being created. If file-based encryption is
              * supported, this broadcast indicates creation of the db in credential-encrypted
              * storage. A boolean is specified in {@link #EXTRA_IS_INITIAL_CREATE} to indicate if
-             * this is the initial create of the db. Requires
-             * {@link android.Manifest.permission#READ_SMS} to receive.
+             * this is the initial create of the db.
              *
              * @see #EXTRA_IS_INITIAL_CREATE
              *
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 15ded8d..e4ba87c 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -94,6 +94,7 @@
     public static final int KM_TAG_ATTESTATION_ID_MEID = KM_BYTES | 715;
     public static final int KM_TAG_ATTESTATION_ID_MANUFACTURER = KM_BYTES | 716;
     public static final int KM_TAG_ATTESTATION_ID_MODEL = KM_BYTES | 717;
+    public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION = KM_BOOL | 720;
 
     public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
     public static final int KM_TAG_NONCE = KM_BYTES | 1001;
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index c9d37bf..52b7294 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1137,6 +1137,7 @@
         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
                 mCallbacks, this, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
+        mWindow.getWindow().setFitWindowInsetsTypes(0 /* types */);
         mWindow.getWindow().addFlags(
                 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
                         WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d5c6766..e50d6c2 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -811,6 +811,7 @@
                         // Add window
                         mLayout.type = mIWallpaperEngine.mWindowType;
                         mLayout.gravity = Gravity.START|Gravity.TOP;
+                        mLayout.setFitWindowInsetsTypes(0 /* types */);
                         mLayout.setTitle(WallpaperService.this.getClass().getName());
                         mLayout.windowAnimations =
                                 com.android.internal.R.style.Animation_Wallpaper;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 236e5ae..1b2db36 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -59,6 +59,7 @@
         DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
         DEFAULT_FLAGS.put("settings_work_profile", "true");
         DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
+        DEFAULT_FLAGS.put("settings_conditionals", "false");
     }
 
     /**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b829c9f..9496827 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -44,6 +44,7 @@
 import android.view.IRotationWatcher;
 import android.view.ISystemGestureExclusionListener;
 import android.view.IWallpaperVisibilityListener;
+import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
 import android.view.KeyEvent;
@@ -120,6 +121,17 @@
     void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
 
     /**
+     * Adds a root container that a client shell can populate with its own windows (usually via
+     * WindowlessWindowManager).
+     *
+     * @param client an IWindow used for window-level communication (ime, finish draw, etc.).
+     * @param windowType used by WM to determine the z-order. This is the same as the window type
+     *                   used in {@link WindowManager.LayoutParams}.
+     * @return a SurfaceControl to add things to.
+     */
+    SurfaceControl addShellRoot(int displayId, IWindow client, int windowType);
+
+    /**
      * Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
      * used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
      * time, so we want to move that off the critical path for starting the new activity.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index bc70d63..43fec82 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -123,6 +123,10 @@
             if (mAnimationControls.isEmpty()) {
                 return;
             }
+            if (mViewRoot.mView == null) {
+                // The view has already detached from window.
+                return;
+            }
 
             mTmpFinishedControls.clear();
             InsetsState state = new InsetsState(mState, true /* copySources */);
@@ -154,6 +158,7 @@
         mFrame.set(frame);
     }
 
+    @Override
     public InsetsState getState() {
         return mState;
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3171306..e3f0da1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -19,12 +19,29 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.View.PFLAG_DRAW_ANIMATION;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 
 import android.Manifest;
@@ -93,6 +110,7 @@
 import android.view.View.AttachInfo;
 import android.view.View.FocusDirection;
 import android.view.View.MeasureSpec;
+import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.accessibility.AccessibilityEvent;
@@ -118,6 +136,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.PhoneFallbackEventHandler;
@@ -519,6 +538,9 @@
 
     private WindowInsets mLastWindowInsets;
 
+    // Insets types hidden by legacy window flags or system UI flags.
+    private @InsetsType int mTypesHiddenByFlags = 0;
+
     /** Last applied configuration obtained from resources. */
     private final Configuration mLastConfigurationFromResources = new Configuration();
     /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */
@@ -890,6 +912,7 @@
                     mOrigWindowType = mWindowAttributes.type;
                     mAttachInfo.mRecomputeGlobalAttributes = true;
                     collectViewAttributes();
+                    adjustLayoutParamsForCompatibility(mWindowAttributes);
                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                             getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
@@ -1841,15 +1864,96 @@
     private int getImpliedSystemUiVisibility(WindowManager.LayoutParams params) {
         int vis = 0;
         // Translucent decor window flags imply stable system ui visibility.
-        if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) {
+        if ((params.flags & FLAG_TRANSLUCENT_STATUS) != 0) {
             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
         }
-        if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) {
+        if ((params.flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
             vis |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
         }
         return vis;
     }
 
+    @VisibleForTesting
+    public static void adjustLayoutParamsForCompatibility(WindowManager.LayoutParams inOutParams) {
+        if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+            return;
+        }
+        final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility;
+        final int flags = inOutParams.flags;
+        final int type = inOutParams.type;
+        final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST;
+
+        if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0) {
+            inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+        } else if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE) != 0) {
+            inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
+        }
+
+        if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) {
+            return;
+        }
+
+        int types = inOutParams.getFitWindowInsetsTypes();
+        int sides = inOutParams.getFitWindowInsetsSides();
+        boolean ignoreVis = inOutParams.getFitIgnoreVisibility();
+
+        if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
+                || (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
+                || (flags & FLAG_TRANSLUCENT_STATUS) != 0) {
+            types &= ~Type.statusBars();
+        }
+        if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                || (flags & FLAG_TRANSLUCENT_NAVIGATION) != 0) {
+            types &= ~Type.systemBars();
+        }
+        if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
+            ignoreVis = true;
+        } else if ((types & Type.systemBars()) == Type.systemBars()
+                && adjust == SOFT_INPUT_ADJUST_RESIZE) {
+            types |= Type.ime();
+        }
+        inOutParams.setFitWindowInsetsTypes(types);
+        inOutParams.setFitWindowInsetsSides(sides);
+        inOutParams.setFitIgnoreVisibility(ignoreVis);
+
+        // The fitting of insets are not really controlled by the clients, so we remove the flag.
+        inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
+    }
+
+    private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
+        if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+            return;
+        }
+        final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
+        final int flags = params.flags;
+        final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
+        final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
+                || (flags & FLAG_FULLSCREEN) != 0;
+        final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
+        final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+
+        @InsetsType int typesToHide = 0;
+        @InsetsType int typesToShow = 0;
+        if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
+            typesToHide |= Type.statusBars();
+        } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
+            typesToShow |= Type.statusBars();
+        }
+        if (navIsHiddenByFlags && !navWasHiddenByFlags) {
+            typesToHide |= Type.navigationBars();
+        } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
+            typesToShow |= Type.navigationBars();
+        }
+        if (typesToHide != 0) {
+            getInsetsController().hide(typesToHide);
+        }
+        if (typesToShow != 0) {
+            getInsetsController().show(typesToShow);
+        }
+        mTypesHiddenByFlags |= typesToHide;
+        mTypesHiddenByFlags &= ~typesToShow;
+    }
+
     private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
             final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
         int childWidthMeasureSpec;
@@ -2271,6 +2375,8 @@
                     && !PixelFormat.formatHasAlpha(params.format)) {
                 params.format = PixelFormat.TRANSLUCENT;
             }
+            adjustLayoutParamsForCompatibility(params);
+            controlInsetsForCompatibility(params);
         }
 
         if (mFirst || windowShouldResize || insetsChanged ||
@@ -2757,7 +2863,7 @@
         if (changedVisibility || regainedFocus) {
             // Toasts are presented as notifications - don't present them as windows as well
             boolean isToast = (mWindowAttributes == null) ? false
-                    : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST);
+                    : (mWindowAttributes.type == TYPE_TOAST);
             if (!isToast) {
                 host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
             }
@@ -4051,7 +4157,7 @@
     }
 
     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
-        final Rect ci = mAttachInfo.mContentInsets;
+        final Rect ci = getWindowInsets(false).getSystemWindowInsetsAsRect();
         final Rect vi = mAttachInfo.mVisibleInsets;
         int scrollY = 0;
         boolean handled = false;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d79abc2..af1882b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -46,6 +46,8 @@
 import android.transition.Scene;
 import android.transition.Transition;
 import android.transition.TransitionManager;
+import android.view.WindowInsets.Side.InsetsSide;
+import android.view.WindowInsets.Type.InsetsType;
 import android.view.accessibility.AccessibilityEvent;
 
 import java.util.Collections;
@@ -1241,6 +1243,60 @@
     }
 
     /**
+     * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsTypes(int)}
+     * @hide pending unhide
+     */
+    public void setFitWindowInsetsTypes(@InsetsType int types) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.setFitWindowInsetsTypes(types);
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsSides(int)}
+     * @hide pending unhide
+     */
+    public void setFitWindowInsetsSides(@InsetsSide int sides) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.setFitWindowInsetsSides(sides);
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * A shortcut for {@link WindowManager.LayoutParams#setFitIgnoreVisibility(boolean)}
+     * @hide pending unhide
+     */
+    public void setFitIgnoreVisibility(boolean ignore) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.setFitIgnoreVisibility(ignore);
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsTypes}
+     * @hide pending unhide
+     */
+    public @InsetsType int getFitWindowInsetsTypes() {
+        return getAttributes().getFitWindowInsetsTypes();
+    }
+
+    /**
+     * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsSides()}
+     * @hide pending unhide
+     */
+    public @InsetsSide int getFitWindowInsetsSides() {
+        return getAttributes().getFitWindowInsetsSides();
+    }
+
+    /**
+     * A shortcut for {@link WindowManager.LayoutParams#getFitIgnoreVisibility()}
+     * @hide pending unhide
+     */
+    public boolean getFitIgnoreVisibility() {
+        return getAttributes().getFitIgnoreVisibility();
+    }
+
+    /**
      * Specify custom window attributes.  <strong>PLEASE NOTE:</strong> the
      * layout params you give here should generally be from values previously
      * retrieved with {@link #getAttributes()}; you probably do not want to
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 57bd5bb..b16a4ca 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -1295,4 +1295,31 @@
             return 0xFFFFFFFF;
         }
     }
+
+    /**
+     * Class that defines different sides for insets.
+     * @hide pending unhide
+     */
+    public static final class Side {
+
+        public static final int LEFT = 1 << 0;
+        public static final int TOP = 1 << 1;
+        public static final int RIGHT = 1 << 2;
+        public static final int BOTTOM = 1 << 3;
+
+        private Side() {
+        }
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag = true, value = {LEFT, TOP, RIGHT, BOTTOM})
+        public @interface InsetsSide {}
+
+        /**
+         * @return all four sides.
+         */
+        public static @InsetsSide int all() {
+            return LEFT | TOP | RIGHT | BOTTOM;
+        }
+    }
 }
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 39e2e73..a045a6a 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -203,4 +203,9 @@
      * @see Behavior
      */
     void setSystemBarsBehavior(@Behavior int behavior);
+
+    /**
+     * @hide
+     */
+    InsetsState getState();
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9d5f98e..34092e2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -17,11 +17,26 @@
 package android.view;
 
 import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
+import static android.view.WindowInsets.Side.BOTTOM;
+import static android.view.WindowInsets.Side.LEFT;
+import static android.view.WindowInsets.Side.RIGHT;
+import static android.view.WindowInsets.Side.TOP;
+import static android.view.WindowInsets.Type.CAPTION_BAR;
+import static android.view.WindowInsets.Type.IME;
+import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.NAVIGATION_BARS;
+import static android.view.WindowInsets.Type.STATUS_BARS;
+import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
+import static android.view.WindowInsets.Type.WINDOW_DECOR;
 import static android.view.WindowLayoutParamsProto.ALPHA;
 import static android.view.WindowLayoutParamsProto.APPEARANCE;
 import static android.view.WindowLayoutParamsProto.BEHAVIOR;
 import static android.view.WindowLayoutParamsProto.BUTTON_BRIGHTNESS;
 import static android.view.WindowLayoutParamsProto.COLOR_MODE;
+import static android.view.WindowLayoutParamsProto.FIT_IGNORE_VISIBILITY;
+import static android.view.WindowLayoutParamsProto.FIT_INSETS_SIDES;
+import static android.view.WindowLayoutParamsProto.FIT_INSETS_TYPES;
 import static android.view.WindowLayoutParamsProto.FLAGS;
 import static android.view.WindowLayoutParamsProto.FORMAT;
 import static android.view.WindowLayoutParamsProto.GRAVITY;
@@ -65,6 +80,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
+import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Side.InsetsSide;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsets.Type.InsetsType;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import java.lang.annotation.Retention;
@@ -1840,6 +1859,20 @@
         public static final int PRIVATE_FLAG_USE_BLAST = 0x02000000;
 
         /**
+         * Flag to indicate that the window is controlling how it fits window insets on its own.
+         * So we don't need to adjust its attributes for fitting window insets.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 0x04000000;
+
+        /**
+         * Flag to indicate that the window only draws the bottom bar background so that we don't
+         * extend it to system bar areas at other sides.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND = 0x08000000;
+
+        /**
          * An internal annotation for flags that can be specified to {@link #softInputMode}.
          *
          * @hide
@@ -1941,7 +1974,15 @@
                 @ViewDebug.FlagToString(
                         mask = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
                         equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
-                        name = "COLOR_SPACE_AGNOSTIC")
+                        name = "COLOR_SPACE_AGNOSTIC"),
+                @ViewDebug.FlagToString(
+                        mask = PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
+                        equals = PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
+                        name = "FIT_INSETS_CONTROLLED"),
+                @ViewDebug.FlagToString(
+                        mask = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND,
+                        equals = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND,
+                        name = "ONLY_DRAW_BOTTOM_BAR_BACKGROUND")
         })
         @TestApi
         public int privateFlags;
@@ -2591,6 +2632,124 @@
          */
         public final InsetsFlags insetsFlags = new InsetsFlags();
 
+        @ViewDebug.ExportedProperty(flagMapping = {
+                @ViewDebug.FlagToString(
+                        mask = STATUS_BARS,
+                        equals = STATUS_BARS,
+                        name = "STATUS_BARS"),
+                @ViewDebug.FlagToString(
+                        mask = NAVIGATION_BARS,
+                        equals = NAVIGATION_BARS,
+                        name = "NAVIGATION_BARS"),
+                @ViewDebug.FlagToString(
+                        mask = CAPTION_BAR,
+                        equals = CAPTION_BAR,
+                        name = "CAPTION_BAR"),
+                @ViewDebug.FlagToString(
+                        mask = IME,
+                        equals = IME,
+                        name = "IME"),
+                @ViewDebug.FlagToString(
+                        mask = SYSTEM_GESTURES,
+                        equals = SYSTEM_GESTURES,
+                        name = "SYSTEM_GESTURES"),
+                @ViewDebug.FlagToString(
+                        mask = MANDATORY_SYSTEM_GESTURES,
+                        equals = MANDATORY_SYSTEM_GESTURES,
+                        name = "MANDATORY_SYSTEM_GESTURES"),
+                @ViewDebug.FlagToString(
+                        mask = TAPPABLE_ELEMENT,
+                        equals = TAPPABLE_ELEMENT,
+                        name = "TAPPABLE_ELEMENT"),
+                @ViewDebug.FlagToString(
+                        mask = WINDOW_DECOR,
+                        equals = WINDOW_DECOR,
+                        name = "WINDOW_DECOR")
+        })
+        private @InsetsType int mFitWindowInsetsTypes = Type.systemBars();
+
+        @ViewDebug.ExportedProperty(flagMapping = {
+                @ViewDebug.FlagToString(
+                        mask = LEFT,
+                        equals = LEFT,
+                        name = "LEFT"),
+                @ViewDebug.FlagToString(
+                        mask = TOP,
+                        equals = TOP,
+                        name = "TOP"),
+                @ViewDebug.FlagToString(
+                        mask = RIGHT,
+                        equals = RIGHT,
+                        name = "RIGHT"),
+                @ViewDebug.FlagToString(
+                        mask = BOTTOM,
+                        equals = BOTTOM,
+                        name = "BOTTOM")
+        })
+        private @InsetsSide int mFitWindowInsetsSides = Side.all();
+
+        private boolean mFitIgnoreVisibility = false;
+
+        /**
+         * Specifies types of insets that this window should avoid overlapping during layout.
+         *
+         * @param types which types of insets that this window should avoid. The initial value of
+         *              this object includes all system bars.
+         * @hide pending unhide
+         */
+        public void setFitWindowInsetsTypes(@InsetsType int types) {
+            mFitWindowInsetsTypes = types;
+            privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
+        }
+
+        /**
+         * Specifies sides of insets that this window should avoid overlapping during layout.
+         *
+         * @param sides which sides that this window should avoid overlapping with the types
+         *              specified. The initial value of this object includes all sides.
+         * @hide pending unhide
+         */
+        public void setFitWindowInsetsSides(@InsetsSide int sides) {
+            mFitWindowInsetsSides = sides;
+            privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
+        }
+
+        /**
+         * Specifies if this window should fit the window insets no matter they are visible or not.
+         *
+         * @param ignore if true, this window will fit the given types even if they are not visible.
+         * @hide pending unhide
+         */
+        public void setFitIgnoreVisibility(boolean ignore) {
+            mFitIgnoreVisibility = ignore;
+            privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
+        }
+
+        /**
+         * @return the insets types that this window is avoiding overlapping.
+         * @hide pending unhide
+         */
+        public @InsetsType int getFitWindowInsetsTypes() {
+            return mFitWindowInsetsTypes;
+        }
+
+        /**
+         * @return the sides that this window is avoiding overlapping.
+         * @hide pending unhide
+         */
+        public @InsetsSide int getFitWindowInsetsSides() {
+            return mFitWindowInsetsSides;
+        }
+
+        /**
+         * @return {@code true} if this window fits the window insets no matter they are visible or
+         *         not.
+         * @hide pending unhide
+         */
+        public boolean getFitIgnoreVisibility() {
+            return mFitIgnoreVisibility;
+        }
+
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = TYPE_APPLICATION;
@@ -2754,6 +2913,9 @@
             out.writeLong(hideTimeoutMilliseconds);
             out.writeInt(insetsFlags.appearance);
             out.writeInt(insetsFlags.behavior);
+            out.writeInt(mFitWindowInsetsTypes);
+            out.writeInt(mFitWindowInsetsSides);
+            out.writeBoolean(mFitIgnoreVisibility);
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -2811,6 +2973,9 @@
             hideTimeoutMilliseconds = in.readLong();
             insetsFlags.appearance = in.readInt();
             insetsFlags.behavior = in.readInt();
+            mFitWindowInsetsTypes = in.readInt();
+            mFitWindowInsetsSides = in.readInt();
+            mFitIgnoreVisibility = in.readBoolean();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -3049,6 +3214,21 @@
                 changes |= INSET_FLAGS_CHANGED;
             }
 
+            if (mFitWindowInsetsTypes != o.mFitWindowInsetsTypes) {
+                mFitWindowInsetsTypes = o.mFitWindowInsetsTypes;
+                changes |= LAYOUT_CHANGED;
+            }
+
+            if (mFitWindowInsetsSides != o.mFitWindowInsetsSides) {
+                mFitWindowInsetsSides = o.mFitWindowInsetsSides;
+                changes |= LAYOUT_CHANGED;
+            }
+
+            if (mFitIgnoreVisibility != o.mFitIgnoreVisibility) {
+                mFitIgnoreVisibility = o.mFitIgnoreVisibility;
+                changes |= LAYOUT_CHANGED;
+            }
+
             return changes;
         }
 
@@ -3203,6 +3383,20 @@
                 sb.append(prefix).append("  bhv=").append(ViewDebug.flagsToString(
                         InsetsFlags.class, "behavior", insetsFlags.behavior));
             }
+            if (mFitWindowInsetsTypes != 0) {
+                sb.append(System.lineSeparator());
+                sb.append(prefix).append("  fitTypes=").append(ViewDebug.flagsToString(
+                        LayoutParams.class, "mFitWindowInsetsTypes", mFitWindowInsetsTypes));
+            }
+            if (mFitWindowInsetsSides != Side.all()) {
+                sb.append(System.lineSeparator());
+                sb.append(prefix).append("  fitSides=").append(ViewDebug.flagsToString(
+                        LayoutParams.class, "mFitWindowInsetsSides", mFitWindowInsetsSides));
+            }
+            if (mFitIgnoreVisibility) {
+                sb.append(System.lineSeparator());
+                sb.append(prefix).append("  fitIgnoreVis");
+            }
 
             sb.append('}');
             return sb.toString();
@@ -3240,6 +3434,9 @@
             proto.write(SUBTREE_SYSTEM_UI_VISIBILITY_FLAGS, subtreeSystemUiVisibility);
             proto.write(APPEARANCE, insetsFlags.appearance);
             proto.write(BEHAVIOR, insetsFlags.behavior);
+            proto.write(FIT_INSETS_TYPES, mFitWindowInsetsTypes);
+            proto.write(FIT_INSETS_SIDES, mFitWindowInsetsSides);
+            proto.write(FIT_IGNORE_VISIBILITY, mFitIgnoreVisibility);
             proto.end(token);
         }
 
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index dc8bf9b..9ab2c2b 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -69,6 +69,8 @@
     private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
     private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
+    private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+
     private boolean mIsAllWindowsCached;
 
     // The SparseArray of all {@link AccessibilityWindowInfo}s on all displays.
@@ -164,16 +166,19 @@
             switch (eventType) {
                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
                     if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                        refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+                        refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
                     }
                     mAccessibilityFocus = event.getSourceNodeId();
-                    refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+                    mAccessibilityFocusedWindow = event.getWindowId();
+                    refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
                 } break;
 
                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
-                    if (mAccessibilityFocus == event.getSourceNodeId()) {
-                        refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+                    if (mAccessibilityFocus == event.getSourceNodeId()
+                            && mAccessibilityFocusedWindow == event.getWindowId()) {
+                        refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
                         mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+                        mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
                     }
                 } break;
 
@@ -210,6 +215,13 @@
                 } break;
 
                 case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
+                    if (event.getWindowChanges()
+                            == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) {
+                        // Don't need to clear all cache. Unless the changes are related to
+                        // content, we won't clear all cache here.
+                        refreshCachedWindowLocked(event.getWindowId());
+                        break;
+                    }
                 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
                     clear();
                 } break;
@@ -243,6 +255,34 @@
         clearSubTreeLocked(windowId, sourceId);
     }
 
+    private void refreshCachedWindowLocked(int windowId) {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "Refreshing cached window.");
+        }
+
+        if (windowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+            return;
+        }
+
+        final int displayCounts = mWindowCacheByDisplay.size();
+        for (int i = 0; i < displayCounts; i++) {
+            final SparseArray<AccessibilityWindowInfo> windowsOfDisplay =
+                    mWindowCacheByDisplay.valueAt(i);
+            if (windowsOfDisplay == null) {
+                continue;
+            }
+            final AccessibilityWindowInfo window = windowsOfDisplay.get(windowId);
+            if (window == null) {
+                continue;
+            }
+            if (!mAccessibilityNodeRefresher.refreshWindow(window)) {
+                // If we fail to refresh the window, clear all windows.
+                clearWindowCacheLocked();
+            }
+            return;
+        }
+    }
+
     /**
      * Gets a cached {@link AccessibilityNodeInfo} given the id of the hosting
      * window and the accessibility id of the node.
@@ -413,8 +453,10 @@
                     refreshCachedNodeLocked(windowId, mAccessibilityFocus);
                 }
                 mAccessibilityFocus = sourceId;
+                mAccessibilityFocusedWindow = windowId;
             } else if (mAccessibilityFocus == sourceId) {
                 mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+                mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
             }
             if (clone.isFocused()) {
                 mInputFocus = sourceId;
@@ -439,6 +481,8 @@
 
             mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
             mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
+            mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
         }
     }
 
@@ -653,8 +697,14 @@
 
     // Layer of indirection included to break dependency chain for testing
     public static class AccessibilityNodeRefresher {
+        /** Refresh the given AccessibilityNodeInfo object. */
         public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
             return info.refresh(null, bypassCache);
         }
+
+        /** Refresh the given AccessibilityWindowInfo object. */
+        public boolean refreshWindow(AccessibilityWindowInfo info) {
+            return info.refresh();
+        }
     }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index bb10ef1..3866517 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -223,19 +223,36 @@
      * @return The {@link AccessibilityWindowInfo}.
      */
     public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId) {
+        return getWindow(connectionId, accessibilityWindowId, /* bypassCache */ false);
+    }
+
+    /**
+     * Gets the info for a window.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param bypassCache Whether to bypass the cache.
+     * @return The {@link AccessibilityWindowInfo}.
+     */
+    public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId,
+            boolean bypassCache) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                AccessibilityWindowInfo window = sAccessibilityCache.getWindow(
-                        accessibilityWindowId);
-                if (window != null) {
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "Window cache hit");
+                AccessibilityWindowInfo window;
+                if (!bypassCache) {
+                    window = sAccessibilityCache.getWindow(accessibilityWindowId);
+                    if (window != null) {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Window cache hit");
+                        }
+                        return window;
                     }
-                    return window;
-                }
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "Window cache miss");
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Window cache miss");
+                    }
                 }
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -244,7 +261,9 @@
                     Binder.restoreCallingIdentity(identityToken);
                 }
                 if (window != null) {
-                    sAccessibilityCache.addWindow(window);
+                    if (!bypassCache) {
+                        sAccessibilityCache.addWindow(window);
+                    }
                     return window;
                 }
             } else {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 2cc6e9a..ca5c417 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -87,6 +87,8 @@
     /** @hide */
     public static final int ACTIVE_WINDOW_ID = Integer.MAX_VALUE;
     /** @hide */
+    public static final int UNDEFINED_CONNECTION_ID = -1;
+    /** @hide */
     public static final int UNDEFINED_WINDOW_ID = -1;
     /** @hide */
     public static final int ANY_WINDOW_ID = -2;
@@ -117,7 +119,7 @@
     private CharSequence mTitle;
     private long mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
 
-    private int mConnectionId = UNDEFINED_WINDOW_ID;
+    private int mConnectionId = UNDEFINED_CONNECTION_ID;
 
     /**
      * Creates a new {@link AccessibilityWindowInfo}.
@@ -539,6 +541,30 @@
         }
     }
 
+    /**
+     * Refreshes this window with the latest state of the window it represents.
+     * <p>
+     * <strong>Note:</strong> If this method returns false this info is obsolete
+     * since it represents a window that is no longer exist.
+     * </p>
+     *
+     * @hide
+     */
+    public boolean refresh() {
+        if (mConnectionId == UNDEFINED_CONNECTION_ID || mId == UNDEFINED_WINDOW_ID) {
+            return false;
+        }
+        final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+        final AccessibilityWindowInfo refreshedInfo = client.getWindow(mConnectionId,
+                mId, /* bypassCache */true);
+        if (refreshedInfo == null) {
+            return false;
+        }
+        init(refreshedInfo);
+        refreshedInfo.recycle();
+        return true;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -586,6 +612,7 @@
         mTitle = other.mTitle;
         mAnchorId = other.mAnchorId;
 
+        if (mChildIds != null) mChildIds.clear();
         if (other.mChildIds != null && other.mChildIds.size() > 0) {
             if (mChildIds == null) {
                 mChildIds = other.mChildIds.clone();
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index bdc2f9a..8f2133f 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -401,6 +401,7 @@
             params.format = PixelFormat.TRANSLUCENT;
             params.windowAnimations = com.android.internal.R.style.Animation_Toast;
             params.type = WindowManager.LayoutParams.TYPE_TOAST;
+            params.setFitIgnoreVisibility(true);
             params.setTitle("Toast");
             params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/telephony/java/com/android/ims/internal/uce/common/CapInfo.aidl b/core/java/com/android/ims/internal/uce/common/CapInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/CapInfo.aidl
rename to core/java/com/android/ims/internal/uce/common/CapInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/CapInfo.java
rename to core/java/com/android/ims/internal/uce/common/CapInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.aidl b/core/java/com/android/ims/internal/uce/common/StatusCode.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/StatusCode.aidl
rename to core/java/com/android/ims/internal/uce/common/StatusCode.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java b/core/java/com/android/ims/internal/uce/common/StatusCode.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/StatusCode.java
rename to core/java/com/android/ims/internal/uce/common/StatusCode.java
diff --git a/telephony/java/com/android/ims/internal/uce/common/UceLong.aidl b/core/java/com/android/ims/internal/uce/common/UceLong.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/UceLong.aidl
rename to core/java/com/android/ims/internal/uce/common/UceLong.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/common/UceLong.java b/core/java/com/android/ims/internal/uce/common/UceLong.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/common/UceLong.java
rename to core/java/com/android/ims/internal/uce/common/UceLong.java
diff --git a/telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl b/core/java/com/android/ims/internal/uce/options/IOptionsListener.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl
rename to core/java/com/android/ims/internal/uce/options/IOptionsListener.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl b/core/java/com/android/ims/internal/uce/options/IOptionsService.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl
rename to core/java/com/android/ims/internal/uce/options/IOptionsService.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl
rename to core/java/com/android/ims/internal/uce/options/OptionsCapInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.java b/core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
rename to core/java/com/android/ims/internal/uce/options/OptionsCapInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl b/core/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl
rename to core/java/com/android/ims/internal/uce/options/OptionsCmdId.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.java b/core/java/com/android/ims/internal/uce/options/OptionsCmdId.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCmdId.java
rename to core/java/com/android/ims/internal/uce/options/OptionsCmdId.java
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl
rename to core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java b/core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
rename to core/java/com/android/ims/internal/uce/options/OptionsCmdStatus.java
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl
rename to core/java/com/android/ims/internal/uce/options/OptionsSipResponse.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
rename to core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl b/core/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
rename to core/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl b/core/java/com/android/ims/internal/uce/presence/IPresenceService.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl
rename to core/java/com/android/ims/internal/uce/presence/IPresenceService.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresCapInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.java b/core/java/com/android/ims/internal/uce/presence/PresCapInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCapInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresCapInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.aidl b/core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresCmdId.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdId.java b/core/java/com/android/ims/internal/uce/presence/PresCmdId.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCmdId.java
rename to core/java/com/android/ims/internal/uce/presence/PresCmdId.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresCmdStatus.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.java b/core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
rename to core/java/com/android/ims/internal/uce/presence/PresCmdStatus.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java b/core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
rename to core/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresResInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresResInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresResInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresResInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresResInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java b/core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresResInstanceInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java b/core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresRlmiInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresServiceInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.java b/core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresServiceInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresServiceInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresSipResponse.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresSipResponse.java
rename to core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl b/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java b/core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java
rename to core/java/com/android/ims/internal/uce/presence/PresSubscriptionState.java
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl
rename to core/java/com/android/ims/internal/uce/presence/PresTupleInfo.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.java b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
rename to core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl b/core/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl
rename to core/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl b/core/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
rename to core/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
rename to core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java b/core/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
similarity index 100%
rename from telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
rename to core/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 2fd5bfd..c64b705 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.app;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.View;
@@ -60,7 +61,7 @@
             @Override
             public void onPageSelected(int position) {
                 mCurrentPage = position;
-                getCurrentListAdapter().rebuildList();
+                getActiveListAdapter().rebuildList();
             }
         });
         viewPager.setAdapter(this);
@@ -89,7 +90,7 @@
     }
 
     UserHandle getCurrentUserHandle() {
-        return getCurrentListAdapter().mResolverListController.getUserHandle();
+        return getActiveListAdapter().mResolverListController.getUserHandle();
     }
 
     @Override
@@ -136,7 +137,17 @@
     abstract Object getAdapterForIndex(int pageIndex);
 
     @VisibleForTesting
-    public abstract ResolverListAdapter getCurrentListAdapter();
+    public abstract ResolverListAdapter getActiveListAdapter();
+
+    /**
+     * If this is a device with a work profile, returns the {@link ResolverListAdapter} instance
+     * of the profile that is not the active one. Otherwise returns {@code null}. For example,
+     * if the share sheet is launched in the work profile, this method returns the personal
+     * profile {@link ResolverListAdapter}.
+     * @see #getActiveListAdapter()
+     */
+    @VisibleForTesting
+    public abstract @Nullable ResolverListAdapter getInactiveListAdapter();
 
     abstract Object getCurrentRootAdapter();
 
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index bb7e4d5..eb74612 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -263,6 +263,7 @@
         mHandler.removeMessages(RANKER_SERVICE_RESULT);
         mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
         afterCompute();
+        mAfterCompute = null;
     }
 
     private boolean isDefaultBrowser(ResolveInfo ri) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1af3926..8856f99 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -362,9 +362,7 @@
                 Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load"
                         + " within " + mImageLoadTimeoutMillis + "ms.");
                 collapseParentView();
-                if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) {
-                    mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview();
-                }
+                hideContentPreview();
                 mHideParentOnFail = false;
             }
         }
@@ -431,14 +429,14 @@
                 logDirectShareTargetReceived(
                         MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
                 sendVoiceChoicesIfNeeded();
-                mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+                mChooserMultiProfilePagerAdapter.getActiveListAdapter()
                         .completeServiceTargetLoading();
             }
         }
 
         @Override
         public void handleMessage(Message msg) {
-            if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter() == null || isDestroyed()) {
+            if (mChooserMultiProfilePagerAdapter.getActiveListAdapter() == null || isDestroyed()) {
                 return;
             }
 
@@ -455,7 +453,7 @@
                     if (sri.resultTargets != null) {
                         // TODO(arangelov): Instead of using getCurrentListAdapter(), pass the
                         // profileId as part of the message.
-                        mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+                        mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
                                 sri.originalTarget, sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET);
                     }
                     unbindService(sri.connection);
@@ -479,14 +477,14 @@
                         Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; ");
                     }
 
-                    mChooserMultiProfilePagerAdapter.getCurrentListAdapter().refreshListView();
+                    mChooserMultiProfilePagerAdapter.getActiveListAdapter().refreshListView();
                     break;
 
                 case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
                     if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT");
                     final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj;
                     if (resultInfo.resultTargets != null) {
-                        mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+                        mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
                                 resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1);
                     }
                     break;
@@ -646,7 +644,7 @@
                 if (isFinishing() || isDestroyed()) {
                     return;
                 }
-                if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
+                if (mChooserMultiProfilePagerAdapter.getActiveListAdapter().getCount() == 0) {
                     return;
                 }
                 if (resultList.isEmpty()) {
@@ -654,12 +652,12 @@
                     //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents.
                     // Investigate implications for work tab.
                     queryDirectShareTargets(
-                            mChooserMultiProfilePagerAdapter.getCurrentListAdapter(), true);
+                            mChooserMultiProfilePagerAdapter.getActiveListAdapter(), true);
                     return;
                 }
                 final List<DisplayResolveInfo> driList =
                         getDisplayResolveInfos(
-                                mChooserMultiProfilePagerAdapter.getCurrentListAdapter());
+                                mChooserMultiProfilePagerAdapter.getActiveListAdapter());
                 final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
                         new ArrayList<>();
                 for (AppTarget appTarget : resultList) {
@@ -809,7 +807,7 @@
 
     @Override
     protected boolean postRebuildList(boolean rebuildCompleted) {
-        mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().maybeLogActionShareWithPreview();
+        updateContentPreview();
         return postRebuildListInternal(rebuildCompleted);
     }
 
@@ -862,7 +860,7 @@
             public void onSomePackagesChanged() {
                 // TODO(arangelov): Dispatch this to all adapters when we have the helper methods
                 // in a follow-up CL
-                mChooserMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
+                mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
                 updateProfileViewButton();
             }
         };
@@ -952,6 +950,12 @@
         }
     }
 
+    private ViewGroup createContentPreviewView(ViewGroup parent) {
+        Intent targetIntent = getTargetIntent();
+        int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+        return displayContentPreview(previewType, targetIntent, getLayoutInflater(), parent);
+    }
+
     private ViewGroup displayContentPreview(@ContentPreviewType int previewType,
             Intent targetIntent, LayoutInflater layoutInflater, ViewGroup parent) {
         ViewGroup layout = null;
@@ -1319,7 +1323,7 @@
     public void onPrepareAdapterView(ResolverListAdapter adapter) {
         mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
         if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
-            mChooserMultiProfilePagerAdapter.getCurrentListAdapter().addServiceResults(
+            mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
                     /* origTarget */ null,
                     Lists.newArrayList(mCallerChooserTargets),
                     TARGET_TYPE_DEFAULT);
@@ -1404,7 +1408,7 @@
     @Override
     public void startSelected(int which, boolean always, boolean filtered) {
         ChooserListAdapter currentListAdapter =
-                mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+                mChooserMultiProfilePagerAdapter.getActiveListAdapter();
         TargetInfo targetInfo = currentListAdapter
                 .targetInfoForPosition(which, filtered);
         if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) {
@@ -1487,7 +1491,7 @@
         String targetPackageName =
                 targetInfo.getChooserTarget().getComponentName().getPackageName();
         ChooserListAdapter currentListAdapter =
-                mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+                mChooserMultiProfilePagerAdapter.getActiveListAdapter();
         int maxRankedResults = Math.min(currentListAdapter.mDisplayList.size(),
                 MAX_LOG_RANK_POSITION);
 
@@ -1841,7 +1845,7 @@
             Intent targetIntent = getTargetIntent();
             if (ri != null && ri.activityInfo != null && targetIntent != null) {
                 ChooserListAdapter currentListAdapter =
-                        mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+                        mChooserMultiProfilePagerAdapter.getActiveListAdapter();
                 if (currentListAdapter != null) {
                     currentListAdapter.updateModel(info.getResolvedComponentName());
                     currentListAdapter.updateChooserCounts(ri.activityInfo.packageName, getUserId(),
@@ -2146,8 +2150,7 @@
                 final int bottomInset = mSystemWindowInsets != null
                                             ? mSystemWindowInsets.bottom : 0;
                 int offset = bottomInset;
-                int rowsToShow = gridAdapter.getContentPreviewRowCount()
-                        + gridAdapter.getProfileRowCount()
+                int rowsToShow = gridAdapter.getProfileRowCount()
                         + gridAdapter.getServiceTargetRowCount()
                         + gridAdapter.getCallerAndRankedTargetRowCount();
 
@@ -2159,13 +2162,17 @@
 
                 // still zero? then use a default height and leave, which
                 // can happen when there are no targets to show
-                if (rowsToShow == 0) {
+                if (rowsToShow == 0 && !shouldShowContentPreview()) {
                     offset += getResources().getDimensionPixelSize(
                             R.dimen.chooser_max_collapsed_height);
                     mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
                     return;
                 }
 
+                if (shouldShowContentPreview()) {
+                    offset += findViewById(R.id.content_preview_container).getHeight();
+                }
+
                 int directShareHeight = 0;
                 rowsToShow = Math.min(4, rowsToShow);
                 for (int i = 0, childCount = recyclerView.getChildCount();
@@ -2216,13 +2223,13 @@
     @Override // ResolverListCommunicator
     public void onHandlePackagesChanged() {
         mServicesRequested.clear();
-        mChooserMultiProfilePagerAdapter.getCurrentListAdapter().notifyDataSetChanged();
+        mChooserMultiProfilePagerAdapter.getActiveListAdapter().notifyDataSetChanged();
         super.onHandlePackagesChanged();
     }
 
     @Override // SelectableTargetInfoCommunicator
     public ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info) {
-        return mChooserMultiProfilePagerAdapter.getCurrentListAdapter().makePresentationGetter(info);
+        return mChooserMultiProfilePagerAdapter.getActiveListAdapter().makePresentationGetter(info);
     }
 
     @Override // SelectableTargetInfoCommunicator
@@ -2244,22 +2251,21 @@
     }
 
     @Override
-    public void onListRebuilt() {
-        final ChooserListAdapter currentListAdapter =
-                mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
-        if (currentListAdapter.mDisplayList == null
-                || currentListAdapter.mDisplayList.isEmpty()) {
-            currentListAdapter.notifyDataSetChanged();
+    public void onListRebuilt(ResolverListAdapter listAdapter) {
+        ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter;
+        if (chooserListAdapter.mDisplayList == null
+                || chooserListAdapter.mDisplayList.isEmpty()) {
+            chooserListAdapter.notifyDataSetChanged();
         } else {
             new AsyncTask<Void, Void, Void>() {
                 @Override
                 protected Void doInBackground(Void... voids) {
-                    currentListAdapter.updateAlphabeticalList();
+                    chooserListAdapter.updateAlphabeticalList();
                     return null;
                 }
                 @Override
                 protected void onPostExecute(Void aVoid) {
-                    currentListAdapter.notifyDataSetChanged();
+                    chooserListAdapter.notifyDataSetChanged();
                 }
             }.execute();
         }
@@ -2275,14 +2281,14 @@
                 Log.d(TAG, "querying direct share targets from ShortcutManager");
             }
 
-            queryDirectShareTargets(currentListAdapter, false);
+            queryDirectShareTargets(chooserListAdapter, false);
         }
         if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
             if (DEBUG) {
                 Log.d(TAG, "List built querying services");
             }
 
-            queryTargetServices(currentListAdapter);
+            queryTargetServices(chooserListAdapter);
         }
     }
 
@@ -2304,10 +2310,43 @@
         return false;
     }
 
+    private boolean shouldShowContentPreview() {
+        return mMultiProfilePagerAdapter.getActiveListAdapter().getCount() > 0
+                && isSendAction(getTargetIntent());
+    }
+
+    private void updateContentPreview() {
+        if (shouldShowContentPreview()) {
+            showContentPreview();
+        } else {
+            hideContentPreview();
+        }
+    }
+
+    private void showContentPreview() {
+        ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container);
+        contentPreviewContainer.setVisibility(View.VISIBLE);
+        ViewGroup contentPreviewView = createContentPreviewView(contentPreviewContainer);
+        contentPreviewContainer.addView(contentPreviewView);
+        logActionShareWithPreview();
+    }
+
+    private void hideContentPreview() {
+        ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container);
+        contentPreviewContainer.removeAllViews();
+        contentPreviewContainer.setVisibility(View.GONE);
+    }
+
+    private void logActionShareWithPreview() {
+        Intent targetIntent = getTargetIntent();
+        int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+        getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+                .setSubtype(previewType));
+    }
+
     /**
      * Used to bind types of individual item including
      * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
-     * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW},
      * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
      * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
      */
@@ -2323,7 +2362,7 @@
                         false/* always */, true/* filterd */));
                 itemView.setOnLongClickListener(v -> {
                     showTargetDetails(
-                            mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+                            mChooserMultiProfilePagerAdapter.getActiveListAdapter()
                                     .resolveInfoForPosition(mListPosition, /* filtered */ true));
                     return true;
                 });
@@ -2368,15 +2407,13 @@
         private int mChooserTargetWidth = 0;
         private boolean mShowAzLabelIfPoss;
 
-        private boolean mHideContentPreview = false;
         private boolean mLayoutRequested = false;
 
         private static final int VIEW_TYPE_DIRECT_SHARE = 0;
         private static final int VIEW_TYPE_NORMAL = 1;
-        private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
-        private static final int VIEW_TYPE_PROFILE = 3;
-        private static final int VIEW_TYPE_AZ_LABEL = 4;
-        private static final int VIEW_TYPE_CALLER_AND_RANK = 5;
+        private static final int VIEW_TYPE_PROFILE = 2;
+        private static final int VIEW_TYPE_AZ_LABEL = 3;
+        private static final int VIEW_TYPE_CALLER_AND_RANK = 4;
 
         private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
         private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
@@ -2433,12 +2470,6 @@
             return maxTargets;
         }
 
-        public void hideContentPreview() {
-            mHideContentPreview = true;
-            mLayoutRequested = true;
-            notifyDataSetChanged();
-        }
-
         public boolean consumeLayoutRequest() {
             boolean oldValue = mLayoutRequested;
             mLayoutRequested = false;
@@ -2447,8 +2478,7 @@
 
         public int getRowCount() {
             return (int) (
-                    getContentPreviewRowCount()
-                            + getProfileRowCount()
+                    getProfileRowCount()
                             + getServiceTargetRowCount()
                             + getCallerAndRankedTargetRowCount()
                             + getAzLabelRowCount()
@@ -2458,19 +2488,6 @@
             );
         }
 
-        public int getContentPreviewRowCount() {
-            if (!isSendAction(getTargetIntent())) {
-                return 0;
-            }
-
-            if (mHideContentPreview || mChooserListAdapter == null
-                    || mChooserListAdapter.getCount() == 0) {
-                return 0;
-            }
-
-            return 1;
-        }
-
         public int getProfileRowCount() {
             return mChooserListAdapter.getOtherProfile() == null ? 0 : 1;
         }
@@ -2499,8 +2516,7 @@
         @Override
         public int getItemCount() {
             return (int) (
-                    getContentPreviewRowCount()
-                            + getProfileRowCount()
+                    getProfileRowCount()
                             + getServiceTargetRowCount()
                             + getCallerAndRankedTargetRowCount()
                             + getAzLabelRowCount()
@@ -2511,8 +2527,6 @@
         @Override
         public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
             switch (viewType) {
-                case VIEW_TYPE_CONTENT_PREVIEW:
-                    return new ItemViewHolder(createContentPreviewView(parent), false);
                 case VIEW_TYPE_PROFILE:
                     return new ItemViewHolder(createProfileView(parent), false);
                 case VIEW_TYPE_AZ_LABEL:
@@ -2547,10 +2561,7 @@
         public int getItemViewType(int position) {
             int count;
 
-            int countSum = (count = getContentPreviewRowCount());
-            if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW;
-
-            countSum += (count = getProfileRowCount());
+            int countSum = (count = getProfileRowCount());
             if (count > 0 && position < countSum) return VIEW_TYPE_PROFILE;
 
             countSum += (count = getServiceTargetRowCount());
@@ -2569,12 +2580,6 @@
             return mChooserListAdapter.getPositionTargetType(getListPosition(position));
         }
 
-        private ViewGroup createContentPreviewView(ViewGroup parent) {
-            Intent targetIntent = getTargetIntent();
-            int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
-            return displayContentPreview(previewType, targetIntent, mLayoutInflater, parent);
-        }
-
         private View createProfileView(ViewGroup parent) {
             View profileRow = mLayoutInflater.inflate(R.layout.chooser_profile_row, parent, false);
             profileRow.setBackground(
@@ -2770,7 +2775,7 @@
         }
 
         int getListPosition(int position) {
-            position -= getContentPreviewRowCount() + getProfileRowCount();
+            position -= getProfileRowCount();
 
             final int serviceCount = mChooserListAdapter.getServiceTargetCount();
             final int serviceRows = (int) Math.ceil((float) serviceCount
@@ -2814,16 +2819,6 @@
             return mChooserListAdapter;
         }
 
-        void maybeLogActionShareWithPreview() {
-            if (getContentPreviewRowCount() == 0) {
-                return;
-            }
-            Intent targetIntent = getTargetIntent();
-            int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
-            getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
-                    .setSubtype(previewType));
-        }
-
         boolean shouldCellSpan(int position) {
             return getItemViewType(position) == VIEW_TYPE_NORMAL;
         }
@@ -3010,7 +3005,7 @@
 
                 // only expand if we have more than maxTargetsPerRow, and delay that decision
                 // until they start to scroll
-                if (mChooserMultiProfilePagerAdapter.getCurrentListAdapter()
+                if (mChooserMultiProfilePagerAdapter.getActiveListAdapter()
                         .getSelectableServiceTargetCount() <= maxTargetsPerRow) {
                     mHideDirectShareExpansion = true;
                     return;
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index aa8ab28..7d856e1 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -102,11 +102,20 @@
 
     @Override
     @VisibleForTesting
-    public ChooserListAdapter getCurrentListAdapter() {
+    public ChooserListAdapter getActiveListAdapter() {
         return getAdapterForIndex(getCurrentPage()).getListAdapter();
     }
 
     @Override
+    @VisibleForTesting
+    public ChooserListAdapter getInactiveListAdapter() {
+        if (getCount() == 1) {
+            return null;
+        }
+        return getAdapterForIndex(1 - getCurrentPage()).getListAdapter();
+    }
+
+    @Override
     ChooserActivity.ChooserGridAdapter getCurrentRootAdapter() {
         return getAdapterForIndex(getCurrentPage());
     }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9cf5e9f..cb7f2e4 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -36,7 +36,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.PermissionChecker;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -240,7 +239,7 @@
         return new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
-                mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
+                mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
                 updateProfileViewButton();
             }
 
@@ -372,7 +371,7 @@
         }
 
         final Set<String> categories = intent.getCategories();
-        MetricsLogger.action(this, mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
+        MetricsLogger.action(this, mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()
                 ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
                 : MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
                 intent.getAction() + ":" + intent.getType() + ":"
@@ -461,7 +460,7 @@
 
     protected void onProfileClick(View v) {
         final DisplayResolveInfo dri =
-                mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
+                mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile();
         if (dri == null) {
             return;
         }
@@ -508,7 +507,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
+        mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
 
         if (mSystemWindowInsets != null) {
             mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
@@ -523,10 +522,10 @@
             return;
         }
 
-        int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getCount();
+        int count = mMultiProfilePagerAdapter.getActiveListAdapter().getCount();
         final Option[] options = new Option[count];
         for (int i = 0, N = options.length; i < N; i++) {
-            TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter().getItem(i);
+            TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter().getItem(i);
             if (target == null) {
                 // If this occurs, a new set of targets is being loaded. Let that complete,
                 // and have the next call to send voice choices proceed instead.
@@ -576,7 +575,7 @@
         }
 
         final DisplayResolveInfo dri =
-                mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile();
+                mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile();
         if (dri != null && !ENABLE_TABBED_VIEW) {
             mProfileView.setVisibility(View.VISIBLE);
             View text = mProfileView.findViewById(R.id.profile_button);
@@ -629,7 +628,7 @@
         // While there may already be a filtered item, we can only use it in the title if the list
         // is already sorted and all information relevant to it is already in the list.
         final boolean named =
-                mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredPosition() >= 0;
+                mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredPosition() >= 0;
         if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
             return getString(defaultTitleRes);
         } else if (isHttpSchemeAndViewAction(intent)) {
@@ -638,14 +637,14 @@
             String dialogTitle = null;
             if (named && !mUseLayoutForBrowsables) {
                 dialogTitle = getString(ActionTitle.BROWSABLE_APP_TITLE_RES,
-                        mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+                        mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredItem()
                                 .getDisplayLabel());
             } else if (named && mUseLayoutForBrowsables) {
                 dialogTitle = getString(ActionTitle.BROWSABLE_HOST_APP_TITLE_RES,
                         intent.getData().getHost(),
-                        mMultiProfilePagerAdapter.getCurrentListAdapter().getFilteredItem()
+                        mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredItem()
                                 .getDisplayLabel());
-            } else if (mMultiProfilePagerAdapter.getCurrentListAdapter().areAllTargetsBrowsers()) {
+            } else if (mMultiProfilePagerAdapter.getActiveListAdapter().areAllTargetsBrowsers()) {
                 dialogTitle = getString(ActionTitle.BROWSABLE_TITLE_RES);
             } else {
                 dialogTitle = getString(ActionTitle.BROWSABLE_HOST_TITLE_RES,
@@ -655,7 +654,7 @@
         } else {
             return named
                     ? getString(title.namedTitleRes, mMultiProfilePagerAdapter
-                            .getCurrentListAdapter().getFilteredItem().getDisplayLabel())
+                            .getActiveListAdapter().getFilteredItem().getDisplayLabel())
                     : getString(title.titleRes);
         }
     }
@@ -673,7 +672,7 @@
             mPackageMonitor.register(this, getMainLooper(), false);
             mRegistered = true;
         }
-        mMultiProfilePagerAdapter.getCurrentListAdapter().handlePackagesChanged();
+        mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
         updateProfileViewButton();
     }
 
@@ -706,8 +705,8 @@
         if (!isChangingConfigurations() && mPickOptionRequest != null) {
             mPickOptionRequest.cancel();
         }
-        if (mMultiProfilePagerAdapter.getCurrentListAdapter() != null) {
-            mMultiProfilePagerAdapter.getCurrentListAdapter().onDestroy();
+        if (mMultiProfilePagerAdapter.getActiveListAdapter() != null) {
+            mMultiProfilePagerAdapter.getActiveListAdapter().onDestroy();
         }
     }
 
@@ -757,7 +756,7 @@
         boolean enabled = false;
         ResolveInfo ri = null;
         if (hasValidSelection) {
-            ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+            ri = mMultiProfilePagerAdapter.getActiveListAdapter()
                     .resolveInfoForPosition(checkedPos, filtered);
             if (ri == null) {
                 Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
@@ -780,12 +779,9 @@
         ActivityInfo activityInfo = ri.activityInfo;
 
         boolean hasRecordPermission =
-                PermissionChecker.checkPermissionForPreflight(
-                        getApplicationContext(),
-                        android.Manifest.permission.RECORD_AUDIO, -1,
-                        activityInfo.applicationInfo.uid,
+                mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO,
                         activityInfo.packageName)
-                        == android.content.pm.PackageManager.PERMISSION_GRANTED;
+                    == android.content.pm.PackageManager.PERMISSION_GRANTED;
 
         if (!hasRecordPermission) {
             // OK, we know the record permission, is this a capture device
@@ -800,7 +796,7 @@
     public void onButtonClick(View v) {
         final int id = v.getId();
         ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
-        ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getCurrentListAdapter();
+        ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
         int which = currentListAdapter.hasFilteredItem()
                 ? currentListAdapter.getFilteredPosition()
                 : listView.getCheckedItemPosition();
@@ -836,7 +832,7 @@
         if (isFinishing()) {
             return;
         }
-        ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+        ResolveInfo ri = mMultiProfilePagerAdapter.getActiveListAdapter()
                 .resolveInfoForPosition(which, hasIndexBeenFiltered);
         if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
             Toast.makeText(this, String.format(getResources().getString(
@@ -846,7 +842,7 @@
             return;
         }
 
-        TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+        TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()
                 .targetInfoForPosition(which, hasIndexBeenFiltered);
         if (target == null) {
             return;
@@ -863,7 +859,7 @@
                         this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
             }
             MetricsLogger.action(this,
-                    mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem()
+                    mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()
                             ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
                             : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
             finish();
@@ -879,18 +875,17 @@
     }
 
     @Override // ResolverListCommunicator
-    public void onPostListReady() {
+    public void onPostListReady(ResolverListAdapter listAdapter) {
         setHeader();
         resetButtonBar();
-        onListRebuilt();
+        onListRebuilt(listAdapter);
     }
 
-    protected void onListRebuilt() {
-        int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
-        if (count == 1 && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
+    protected void onListRebuilt(ResolverListAdapter listAdapter) {
+        int count = listAdapter.getUnfilteredCount();
+        if (count == 1 && listAdapter.getOtherProfile() == null) {
             // Only one target, so we're a candidate to auto-launch!
-            final TargetInfo target =
-                    mMultiProfilePagerAdapter.getCurrentListAdapter().targetInfoForPosition(0, false);
+            final TargetInfo target = listAdapter.targetInfoForPosition(0, false);
             if (shouldAutoLaunchSingleChoice(target)) {
                 safelyStartActivity(target);
                 finish();
@@ -903,8 +898,8 @@
         final Intent intent = target != null ? target.getResolvedIntent() : null;
 
         if (intent != null && (mSupportsAlwaysUseOption
-                || mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem())
-                && mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredResolveList() != null) {
+                || mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem())
+                && mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredResolveList() != null) {
             // Build a reasonable intent filter, based on what matched.
             IntentFilter filter = new IntentFilter();
             Intent filterIntent;
@@ -989,14 +984,14 @@
             }
 
             if (filter != null) {
-                final int N = mMultiProfilePagerAdapter.getCurrentListAdapter()
+                final int N = mMultiProfilePagerAdapter.getActiveListAdapter()
                         .getUnfilteredResolveList().size();
                 ComponentName[] set;
                 // If we don't add back in the component for forwarding the intent to a managed
                 // profile, the preferred activity may not be updated correctly (as the set of
                 // components we tell it we knew about will have changed).
                 final boolean needToAddBackProfileForwardingComponent =
-                        mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() != null;
+                        mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null;
                 if (!needToAddBackProfileForwardingComponent) {
                     set = new ComponentName[N];
                 } else {
@@ -1005,7 +1000,7 @@
 
                 int bestMatch = 0;
                 for (int i=0; i<N; i++) {
-                    ResolveInfo r = mMultiProfilePagerAdapter.getCurrentListAdapter()
+                    ResolveInfo r = mMultiProfilePagerAdapter.getActiveListAdapter()
                             .getUnfilteredResolveList().get(i).getResolveInfoAt(0);
                     set[i] = new ComponentName(r.activityInfo.packageName,
                             r.activityInfo.name);
@@ -1013,9 +1008,9 @@
                 }
 
                 if (needToAddBackProfileForwardingComponent) {
-                    set[N] = mMultiProfilePagerAdapter.getCurrentListAdapter()
+                    set[N] = mMultiProfilePagerAdapter.getActiveListAdapter()
                             .getOtherProfile().getResolvedComponentName();
-                    final int otherProfileMatch = mMultiProfilePagerAdapter.getCurrentListAdapter()
+                    final int otherProfileMatch = mMultiProfilePagerAdapter.getActiveListAdapter()
                             .getOtherProfile().getResolveInfo().match;
                     if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch;
                 }
@@ -1055,7 +1050,7 @@
                     }
                 } else {
                     try {
-                        mMultiProfilePagerAdapter.getCurrentListAdapter()
+                        mMultiProfilePagerAdapter.getActiveListAdapter()
                                 .mResolverListController.setLastChosen(intent, filter, bestMatch);
                     } catch (RemoteException re) {
                         Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
@@ -1200,10 +1195,14 @@
      * @return <code>true</code> if the activity is finishing and creation should halt.
      */
     private boolean configureContentView() {
-        if (mMultiProfilePagerAdapter.getCurrentListAdapter() == null) {
-            throw new IllegalStateException("mAdapter cannot be null.");
+        if (mMultiProfilePagerAdapter.getActiveListAdapter() == null) {
+            throw new IllegalStateException("mMultiProfilePagerAdapter.getCurrentListAdapter() "
+                    + "cannot be null.");
         }
-        boolean rebuildCompleted = mMultiProfilePagerAdapter.getCurrentListAdapter().rebuildList();
+        boolean rebuildCompleted = mMultiProfilePagerAdapter.getActiveListAdapter().rebuildList();
+        if (mMultiProfilePagerAdapter.getInactiveListAdapter() != null) {
+            mMultiProfilePagerAdapter.getInactiveListAdapter().rebuildList();
+        }
         if (useLayoutWithDefault()) {
             mLayoutId = R.layout.resolver_list_with_default;
         } else {
@@ -1231,15 +1230,15 @@
      */
     final boolean postRebuildListInternal(boolean rebuildCompleted) {
 
-        int count = mMultiProfilePagerAdapter.getCurrentListAdapter().getUnfilteredCount();
+        int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();
 
         // We only rebuild asynchronously when we have multiple elements to sort. In the case where
         // we're already done, we can check if we should auto-launch immediately.
         if (rebuildCompleted) {
             if (count == 1
-                    && mMultiProfilePagerAdapter.getCurrentListAdapter().getOtherProfile() == null) {
+                    && mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() == null) {
                 // Only one target, so we're a candidate to auto-launch!
-                final TargetInfo target = mMultiProfilePagerAdapter.getCurrentListAdapter()
+                final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()
                         .targetInfoForPosition(0, false);
                 if (shouldAutoLaunchSingleChoice(target)) {
                     safelyStartActivity(target);
@@ -1257,12 +1256,12 @@
 
     private void setupViewVisibilities(int count) {
         if (count == 0
-                && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
+                && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) {
             final TextView emptyView = findViewById(R.id.empty);
             emptyView.setVisibility(View.VISIBLE);
             findViewById(R.id.profile_pager).setVisibility(View.GONE);
         } else {
-            onPrepareAdapterView(mMultiProfilePagerAdapter.getCurrentListAdapter());
+            onPrepareAdapterView(mMultiProfilePagerAdapter.getActiveListAdapter());
         }
     }
 
@@ -1295,8 +1294,8 @@
      * Configure the area above the app selection list (title, content preview, etc).
      */
     public void setHeader() {
-        if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0
-                && mMultiProfilePagerAdapter.getCurrentListAdapter().getPlaceholderCount() == 0) {
+        if (mMultiProfilePagerAdapter.getActiveListAdapter().getCount() == 0
+                && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) {
             final TextView titleView = findViewById(R.id.title);
             if (titleView != null) {
                 titleView.setVisibility(View.GONE);
@@ -1317,7 +1316,7 @@
 
         final ImageView iconView = findViewById(R.id.icon);
         if (iconView != null) {
-            mMultiProfilePagerAdapter.getCurrentListAdapter().loadFilteredItemIconTaskAsync(iconView);
+            mMultiProfilePagerAdapter.getActiveListAdapter().loadFilteredItemIconTaskAsync(iconView);
         }
     }
 
@@ -1345,7 +1344,7 @@
     }
 
     private void resetAlwaysOrOnceButtonBar() {
-        int filteredPosition = mMultiProfilePagerAdapter.getCurrentListAdapter()
+        int filteredPosition = mMultiProfilePagerAdapter.getActiveListAdapter()
                 .getFilteredPosition();
         if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
             setAlwaysButtonEnabled(true, filteredPosition, false);
@@ -1365,7 +1364,7 @@
     @Override // ResolverListCommunicator
     public boolean useLayoutWithDefault() {
         return mSupportsAlwaysUseOption
-                && mMultiProfilePagerAdapter.getCurrentListAdapter().hasFilteredItem();
+                && mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem();
     }
 
     /**
@@ -1389,7 +1388,9 @@
 
     @Override // ResolverListCommunicator
     public void onHandlePackagesChanged() {
-        if (mMultiProfilePagerAdapter.getCurrentListAdapter().getCount() == 0) {
+        ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
+        activeListAdapter.rebuildList();
+        if (activeListAdapter.getCount() == 0) {
             // We no longer have any items...  just finish the activity.
             finish();
         }
@@ -1464,7 +1465,7 @@
                 return;
             }
             // If we're still loading, we can't yet enable the buttons.
-            if (mMultiProfilePagerAdapter.getCurrentListAdapter()
+            if (mMultiProfilePagerAdapter.getActiveListAdapter()
                     .resolveInfoForPosition(position, true) == null) {
                 return;
             }
@@ -1497,7 +1498,7 @@
                 // Header views don't count.
                 return false;
             }
-            ResolveInfo ri = mMultiProfilePagerAdapter.getCurrentListAdapter()
+            ResolveInfo ri = mMultiProfilePagerAdapter.getActiveListAdapter()
                     .resolveInfoForPosition(position, true);
             showTargetDetails(ri);
             return true;
@@ -1538,7 +1539,7 @@
 
             final ResolverActivity ra = (ResolverActivity) getActivity();
             if (ra != null) {
-                final TargetInfo ti = ra.mMultiProfilePagerAdapter.getCurrentListAdapter()
+                final TargetInfo ti = ra.mMultiProfilePagerAdapter.getActiveListAdapter()
                         .getItem(selections[0].getIndex());
                 if (ra.onTargetSelected(ti, false)) {
                     ra.mPickOptionRequest = null;
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 48064da..ef7a347 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -113,7 +113,6 @@
     }
 
     public void handlePackagesChanged() {
-        rebuildList();
         mResolverListCommunicator.onHandlePackagesChanged();
     }
 
@@ -351,12 +350,12 @@
      * determine the layout known. We therefore can't update the UI inline and post to the
      * handler thread to update after the current task is finished.
      */
-    private void postListReadyRunnable() {
+    void postListReadyRunnable() {
         if (mPostListReadyRunnable == null) {
             mPostListReadyRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    mResolverListCommunicator.onPostListReady();
+                    mResolverListCommunicator.onPostListReady(ResolverListAdapter.this);
                     mPostListReadyRunnable = null;
                 }
             };
@@ -599,7 +598,7 @@
 
         Intent getReplacementIntent(ActivityInfo activityInfo, Intent defIntent);
 
-        void onPostListReady();
+        void onPostListReady(ResolverListAdapter listAdapter);
 
         void sendVoiceChoicesIfNeeded();
 
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 9e814ab..d72c52b 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -87,13 +87,22 @@
 
     @Override
     @VisibleForTesting
-    public ResolverListAdapter getCurrentListAdapter() {
+    public ResolverListAdapter getActiveListAdapter() {
         return getAdapterForIndex(getCurrentPage());
     }
 
     @Override
+    @VisibleForTesting
+    public ResolverListAdapter getInactiveListAdapter() {
+        if (getCount() == 1) {
+            return null;
+        }
+        return getAdapterForIndex(1 - getCurrentPage());
+    }
+
+    @Override
     ResolverListAdapter getCurrentRootAdapter() {
-        return getCurrentListAdapter();
+        return getActiveListAdapter();
     }
 
     @Override
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7140e7e..d0a83c4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.os;
 
+import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
+import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index c33b6dc..29b148c 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -22,6 +22,8 @@
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.os.Build.VERSION_CODES.M;
 import static android.os.Build.VERSION_CODES.N;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -74,6 +76,8 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.InputQueue;
+import android.view.InsetsState;
+import android.view.InsetsState.InternalInsetsType;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.LayoutInflater;
@@ -90,6 +94,9 @@
 import android.view.Window;
 import android.view.WindowCallbacks;
 import android.view.WindowInsets;
+import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsetsController;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -134,7 +141,7 @@
                     Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
                     Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
                     com.android.internal.R.id.statusBarBackground,
-                    FLAG_FULLSCREEN);
+                    FLAG_FULLSCREEN, ITYPE_STATUS_BAR);
 
     public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
             new ColorViewAttributes(
@@ -142,7 +149,7 @@
                     Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
                     Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
                     com.android.internal.R.id.navigationBarBackground,
-                    0 /* hideWindowFlag */);
+                    0 /* hideWindowFlag */, ITYPE_NAVIGATION_BAR);
 
     // This is used to workaround an issue where the PiP shadow can be transparent if the window
     // background is transparent
@@ -1085,6 +1092,9 @@
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
 
+        final WindowInsetsController controller = getWindowInsetsController();
+        final InsetsState state = controller != null ? controller.getState() : null;
+
         // IME is an exceptional floating window that requires color view.
         final boolean isImeWindow =
                 mWindow.getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -1133,7 +1143,7 @@
                     calculateNavigationBarColor(), mWindow.mNavigationBarDividerColor, navBarSize,
                     navBarToRightEdge || navBarToLeftEdge, navBarToLeftEdge,
                     0 /* sideInset */, animate && !disallowAnimate,
-                    mForceWindowDrawsBarBackgrounds);
+                    mForceWindowDrawsBarBackgrounds, state);
             boolean oldDrawLegacy = mDrawLegacyNavigationBarBackground;
             mDrawLegacyNavigationBarBackground = mNavigationColorViewState.visible
                     && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0;
@@ -1154,7 +1164,7 @@
                     calculateStatusBarColor(), 0, mLastTopInset,
                     false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,
                     animate && !disallowAnimate,
-                    mForceWindowDrawsBarBackgrounds);
+                    mForceWindowDrawsBarBackgrounds, state);
         }
 
         // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or
@@ -1164,16 +1174,19 @@
         // Note: We don't need to check for IN_SCREEN or INSET_DECOR because unlike the status bar,
         // these flags wouldn't make the window draw behind the navigation bar, unless
         // LAYOUT_HIDE_NAVIGATION was set.
-        boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+        boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                || !(state == null || state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
         boolean forceConsumingNavBar = (mForceWindowDrawsBarBackgrounds
                         && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
+                        && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
                         && !hideNavigation)
                 || (mLastShouldAlwaysConsumeSystemBars && hideNavigation);
 
         boolean consumingNavBar =
                 ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                         && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
+                        && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
                         && !hideNavigation)
                 || forceConsumingNavBar;
 
@@ -1182,18 +1195,21 @@
         // If we should always consume system bars, only consume that if the app wanted to go to
         // fullscreen, as othrewise we can expect the app to handle it.
         boolean fullscreen = (sysUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) != 0
-                || (attrs.flags & FLAG_FULLSCREEN) != 0;
+                || (attrs.flags & FLAG_FULLSCREEN) != 0
+                || !(state == null || state.getSource(ITYPE_STATUS_BAR).isVisible());
         boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
                 && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
                 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
+                && (attrs.getFitWindowInsetsTypes() & Type.statusBars()) != 0
                 && mForceWindowDrawsBarBackgrounds
                 && mLastTopInset != 0
                 || (mLastShouldAlwaysConsumeSystemBars && fullscreen);
 
-        int consumedTop = consumingStatusBar ? mLastTopInset : 0;
-        int consumedRight = consumingNavBar ? mLastRightInset : 0;
-        int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
-        int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
+        int sides = attrs.getFitWindowInsetsSides();
+        int consumedTop = consumingStatusBar && (sides & Side.TOP) != 0 ? mLastTopInset : 0;
+        int consumedRight = consumingNavBar && (sides & Side.RIGHT) != 0 ? mLastRightInset : 0;
+        int consumedBottom = consumingNavBar && (sides & Side.BOTTOM) != 0 ? mLastBottomInset : 0;
+        int consumedLeft = consumingNavBar && (sides & Side.LEFT) != 0 ? mLastLeftInset : 0;
 
         if (mContentRoot != null
                 && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
@@ -1325,8 +1341,10 @@
      */
     private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
             int dividerColor, int size, boolean verticalBar, boolean seascape, int sideMargin,
-            boolean animate, boolean force) {
-        state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
+            boolean animate, boolean force, InsetsState insetsState) {
+        state.present = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
+                ? state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force)
+                : state.attributes.isPresent(insetsState, mWindow.getAttributes().flags, force);
         boolean show = state.attributes.isVisible(state.present, color,
                 mWindow.getAttributes().flags, force);
         boolean showView = show && !isResizing() && size > 0;
@@ -2536,10 +2554,11 @@
         final int seascapeGravity;
         final String transitionName;
         final int hideWindowFlag;
+        final @InternalInsetsType int insetsType;
 
         private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
                 int horizontalGravity, int seascapeGravity, String transitionName, int id,
-                int hideWindowFlag) {
+                int hideWindowFlag, @InternalInsetsType int insetsType) {
             this.id = id;
             this.systemUiHideFlag = systemUiHideFlag;
             this.translucentFlag = translucentFlag;
@@ -2548,8 +2567,10 @@
             this.seascapeGravity = seascapeGravity;
             this.transitionName = transitionName;
             this.hideWindowFlag = hideWindowFlag;
+            this.insetsType = insetsType;
         }
 
+        // TODO(b/118118435): remove after migration
         public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
             return (sysUiVis & systemUiHideFlag) == 0
                     && (windowFlags & hideWindowFlag) == 0
@@ -2557,16 +2578,27 @@
                     || force);
         }
 
+        public boolean isPresent(InsetsState state, int windowFlags, boolean force) {
+            return (state == null || state.getSource(insetsType).isVisible())
+                    && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || force);
+        }
+
         public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
             return present
                     && (color & Color.BLACK) != 0
                     && ((windowFlags & translucentFlag) == 0  || force);
         }
 
+        // TODO(b/118118435): remove after migration
         public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
             final boolean present = isPresent(sysUiVis, windowFlags, force);
             return isVisible(present, color, windowFlags, force);
         }
+
+        public boolean isVisible(InsetsState state, int color, int windowFlags, boolean force) {
+            final boolean present = isPresent(state, windowFlags, force);
+            return isVisible(present, color, windowFlags, force);
+        }
     }
 
     /**
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 49a73ee..7562bad 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -222,6 +222,8 @@
     private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>();
     private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>();
 
+    private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
+
     /**
      * Map of system pre-defined, uniquely named actors; keys are namespace,
      * value maps actor name to package name.
@@ -382,6 +384,10 @@
         return mBugreportWhitelistedPackages;
     }
 
+    public Set<String> getRollbackWhitelistedPackages() {
+        return mRollbackWhitelistedPackages;
+    }
+
     /**
      * Gets map of packagesNames to userTypes, dictating on which user types each package should be
      * initially installed, and then removes this map from SystemConfig.
@@ -1078,6 +1084,16 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "rollback-whitelisted-app": {
+                        String pkgname = parser.getAttributeValue(null, "package");
+                        if (pkgname == null) {
+                            Slog.w(TAG, "<" + name + "> without package in " + permFile
+                                    + " at " + parser.getPositionDescription());
+                        } else {
+                            mRollbackWhitelistedPackages.add(pkgname);
+                        }
+                        XmlUtils.skipCurrentTag(parser);
+                    } break;
                     default: {
                         Slog.w(TAG, "Tag " + name + " is unknown in "
                                 + permFile + " at " + parser.getPositionDescription());
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index 1290026..6c2a5a3 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -25,6 +25,7 @@
 #include <SkPicture.h>
 #include <SkPictureRecorder.h>
 #include <hwui/AnimatedImageDrawable.h>
+#include <hwui/ImageDecoder.h>
 #include <hwui/Canvas.h>
 #include <utils/Looper.h>
 
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 4d907f6..627f8f5 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -20,10 +20,12 @@
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "GraphicsJNI.h"
 #include "ImageDecoder.h"
+#include "NinePatchPeeker.h"
 #include "Utils.h"
 #include "core_jni_helpers.h"
 
 #include <hwui/Bitmap.h>
+#include <hwui/ImageDecoder.h>
 #include <HardwareBitmapUploader.h>
 
 #include <SkAndroidCodec.h>
@@ -49,6 +51,28 @@
 static jmethodID gCanvas_constructorMethodID;
 static jmethodID gCanvas_releaseMethodID;
 
+// These need to stay in sync with ImageDecoder.java's Allocator constants.
+enum Allocator {
+    kDefault_Allocator      = 0,
+    kSoftware_Allocator     = 1,
+    kSharedMemory_Allocator = 2,
+    kHardware_Allocator     = 3,
+};
+
+// These need to stay in sync with ImageDecoder.java's Error constants.
+enum Error {
+    kSourceException     = 1,
+    kSourceIncomplete    = 2,
+    kSourceMalformedData = 3,
+};
+
+// These need to stay in sync with PixelFormat.java's Format constants.
+enum PixelFormat {
+    kUnknown     =  0,
+    kTranslucent = -3,
+    kOpaque      = -1,
+};
+
 // Clear and return any pending exception for handling other than throwing directly.
 static jthrowable get_and_clear_exception(JNIEnv* env) {
     jthrowable jexception = env->ExceptionOccurred();
@@ -59,7 +83,7 @@
 }
 
 // Throw a new ImageDecoder.DecodeException. Returns null for convenience.
-static jobject throw_exception(JNIEnv* env, ImageDecoder::Error error, const char* msg,
+static jobject throw_exception(JNIEnv* env, Error error, const char* msg,
                                jthrowable cause, jobject source) {
     jstring jstr = nullptr;
     if (msg) {
@@ -81,27 +105,27 @@
 static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
         jobject source, jboolean preferAnimation) {
     if (!stream.get()) {
-        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+        return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
                                nullptr, source);
     }
-    std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
+    sk_sp<NinePatchPeeker> peeker(new NinePatchPeeker);
     SkCodec::Result result;
     auto codec = SkCodec::MakeFromStream(
-            std::move(stream), &result, decoder->mPeeker.get(),
+            std::move(stream), &result, peeker.get(),
             preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
                             : SkCodec::SelectionPolicy::kPreferStillImage);
     if (jthrowable jexception = get_and_clear_exception(env)) {
-        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+        return throw_exception(env, kSourceException, "", jexception, source);
     }
     if (!codec) {
         switch (result) {
             case SkCodec::kIncompleteInput:
-                return throw_exception(env, ImageDecoder::kSourceIncomplete, "", nullptr, source);
+                return throw_exception(env, kSourceIncomplete, "", nullptr, source);
             default:
                 SkString msg;
                 msg.printf("Failed to create image decoder with message '%s'",
                            SkCodec::ResultToString(result));
-                return throw_exception(env, ImageDecoder::kSourceMalformedData,  msg.c_str(),
+                return throw_exception(env, kSourceMalformedData,  msg.c_str(),
                                        nullptr, source);
 
         }
@@ -109,21 +133,22 @@
 
     const bool animated = codec->getFrameCount() > 1;
     if (jthrowable jexception = get_and_clear_exception(env)) {
-        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+        return throw_exception(env, kSourceException, "", jexception, source);
     }
 
-    decoder->mCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
+    auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
             SkAndroidCodec::ExifOrientationBehavior::kRespect);
-    if (!decoder->mCodec.get()) {
-        return throw_exception(env, ImageDecoder::kSourceMalformedData, "", nullptr, source);
+    if (!androidCodec.get()) {
+        return throw_exception(env, kSourceMalformedData, "", nullptr, source);
     }
 
-    const auto& info = decoder->mCodec->getInfo();
+    const auto& info = androidCodec->getInfo();
     const int width = info.width();
     const int height = info.height();
-    const bool isNinePatch = decoder->mPeeker->mPatch != nullptr;
+    const bool isNinePatch = peeker->mPatch != nullptr;
+    ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker));
     return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
-                          reinterpret_cast<jlong>(decoder.release()), width, height,
+                          reinterpret_cast<jlong>(decoder), width, height,
                           animated, isNinePatch);
 }
 
@@ -133,7 +158,7 @@
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
-        return throw_exception(env, ImageDecoder::kSourceMalformedData,
+        return throw_exception(env, kSourceMalformedData,
                                "broken file descriptor; fstat returned -1", nullptr, source);
     }
 
@@ -141,7 +166,7 @@
     FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
         close(dupDescriptor);
-        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Could not open file",
+        return throw_exception(env, kSourceMalformedData, "Could not open file",
                                nullptr, source);
     }
 
@@ -154,7 +179,7 @@
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
 
     if (!stream.get()) {
-        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+        return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
                                nullptr, source);
     }
 
@@ -177,7 +202,7 @@
     std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
                                                                      initialPosition, limit);
     if (!stream) {
-        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer",
+        return throw_exception(env, kSourceMalformedData, "Failed to read ByteBuffer",
                                nullptr, source);
     }
     return native_create(env, std::move(stream), source, preferAnimation);
@@ -195,7 +220,7 @@
                                      reinterpret_cast<jlong>(canvas.get()));
     if (!jcanvas) {
         doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
-        return ImageDecoder::kUnknown;
+        return kUnknown;
     }
 
     // jcanvas now owns canvas.
@@ -206,43 +231,23 @@
 
 static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                           jobject jdecoder, jboolean jpostProcess,
-                                          jint desiredWidth, jint desiredHeight, jobject jsubset,
+                                          jint targetWidth, jint targetHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
                                           jboolean asAlphaMask, jlong colorSpaceHandle,
                                           jboolean extended) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
-    SkAndroidCodec* codec = decoder->mCodec.get();
-    const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
-    SkISize decodeSize = desiredSize;
-    const int sampleSize = codec->computeSampleSize(&decodeSize);
-    const bool scale = desiredSize != decodeSize;
-    SkImageInfo decodeInfo = codec->getInfo().makeWH(decodeSize.width(), decodeSize.height());
-    if (scale && requireUnpremul && kOpaque_SkAlphaType != decodeInfo.alphaType()) {
+    if (!decoder->setTargetSize(targetWidth, targetHeight)) {
+        doThrowISE(env, "Could not scale to target size!");
+        return nullptr;
+    }
+    if (requireUnpremul && !decoder->setOutAlphaType(kUnpremul_SkAlphaType)) {
         doThrowISE(env, "Cannot scale unpremultiplied pixels!");
         return nullptr;
     }
 
-    switch (decodeInfo.alphaType()) {
-        case kUnpremul_SkAlphaType:
-            if (!requireUnpremul) {
-                decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType);
-            }
-            break;
-        case kPremul_SkAlphaType:
-            if (requireUnpremul) {
-                decodeInfo = decodeInfo.makeAlphaType(kUnpremul_SkAlphaType);
-            }
-            break;
-        case kOpaque_SkAlphaType:
-            break;
-        case kUnknown_SkAlphaType:
-            doThrowIOE(env, "Unknown alpha type");
-            return nullptr;
-    }
-
     SkColorType colorType = kN32_SkColorType;
-    if (asAlphaMask && decodeInfo.colorType() == kGray_8_SkColorType) {
+    if (asAlphaMask && decoder->gray()) {
         // We have to trick Skia to decode this to a single channel.
         colorType = kGray_8_SkColorType;
     } else if (preferRamOverQuality) {
@@ -250,12 +255,12 @@
         // result incorrect. If we call the postProcess before now and record
         // to a picture, we can know whether alpha was added, and if not, we
         // can still use 565.
-        if (decodeInfo.alphaType() == kOpaque_SkAlphaType && !jpostProcess) {
+        if (decoder->opaque() && !jpostProcess) {
             // If the final result will be hardware, decoding to 565 and then
             // uploading to the gpu as 8888 will not save memory. This still
             // may save us from using F16, but do not go down to 565.
-            if (allocator != ImageDecoder::kHardware_Allocator &&
-               (allocator != ImageDecoder::kDefault_Allocator || requireMutable)) {
+            if (allocator != kHardware_Allocator &&
+               (allocator != kDefault_Allocator || requireMutable)) {
                 colorType = kRGB_565_SkColorType;
             }
         }
@@ -263,12 +268,12 @@
     } else if (extended) {
         colorType = kRGBA_F16_SkColorType;
     } else {
-        colorType = codec->computeOutputColorType(colorType);
+        colorType = decoder->mCodec->computeOutputColorType(colorType);
     }
 
     const bool isHardware = !requireMutable
-        && (allocator == ImageDecoder::kDefault_Allocator ||
-            allocator == ImageDecoder::kHardware_Allocator)
+        && (allocator == kDefault_Allocator ||
+            allocator == kHardware_Allocator)
         && colorType != kGray_8_SkColorType;
 
     if (colorType == kRGBA_F16_SkColorType && isHardware &&
@@ -276,12 +281,28 @@
         colorType = kN32_SkColorType;
     }
 
-    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
-    colorSpace = codec->computeOutputColorSpace(colorType, colorSpace);
-    decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace);
+    if (!decoder->setOutColorType(colorType)) {
+        doThrowISE(env, "Failed to set out color type!");
+        return nullptr;
+    }
+
+    {
+        sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
+        colorSpace = decoder->mCodec->computeOutputColorSpace(colorType, colorSpace);
+        decoder->setOutColorSpace(std::move(colorSpace));
+    }
+
+    if (jsubset) {
+        SkIRect subset;
+        GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
+        if (!decoder->setCropRect(&subset)) {
+            doThrowISE(env, "Invalid crop rect!");
+            return nullptr;
+        }
+    }
 
     SkBitmap bm;
-    auto bitmapInfo = decodeInfo;
+    SkImageInfo bitmapInfo = decoder->getOutputInfo();
     if (asAlphaMask && colorType == kGray_8_SkColorType) {
         bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
     }
@@ -291,10 +312,7 @@
     }
 
     sk_sp<Bitmap> nativeBitmap;
-    // If we are going to scale or subset, we will create a new bitmap later on,
-    // so use the heap for the temporary.
-    // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
-    if (allocator == ImageDecoder::kSharedMemory_Allocator && !scale && !jsubset) {
+    if (allocator == kSharedMemory_Allocator) {
         nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
     } else {
         nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
@@ -302,16 +320,14 @@
     if (!nativeBitmap) {
         SkString msg;
         msg.printf("OOM allocating Bitmap with dimensions %i x %i",
-                decodeInfo.width(), decodeInfo.height());
+                bitmapInfo.width(), bitmapInfo.height());
         doThrowOOME(env, msg.c_str());
         return nullptr;
     }
 
-    SkAndroidCodec::AndroidOptions options;
-    options.fSampleSize = sampleSize;
-    auto result = codec->getAndroidPixels(decodeInfo, bm.getPixels(), bm.rowBytes(), &options);
+    SkCodec::Result result = decoder->decode(bm.getPixels(), bm.rowBytes());
     jthrowable jexception = get_and_clear_exception(env);
-    int onPartialImageError = jexception ? ImageDecoder::kSourceException
+    int onPartialImageError = jexception ? kSourceException
                                          : 0; // No error.
     switch (result) {
         case SkCodec::kSuccess:
@@ -321,12 +337,12 @@
             break;
         case SkCodec::kIncompleteInput:
             if (!jexception) {
-                onPartialImageError = ImageDecoder::kSourceIncomplete;
+                onPartialImageError = kSourceIncomplete;
             }
             break;
         case SkCodec::kErrorInInput:
             if (!jexception) {
-                onPartialImageError = ImageDecoder::kSourceMalformedData;
+                onPartialImageError = kSourceMalformedData;
             }
             break;
         default:
@@ -350,20 +366,21 @@
     // Ignore ninepatch when post-processing.
     if (!jpostProcess) {
         // FIXME: Share more code with BitmapFactory.cpp.
-        if (decoder->mPeeker->mPatch != nullptr) {
-            size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
+        auto* peeker = reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get());
+        if (peeker->mPatch != nullptr) {
+            size_t ninePatchArraySize = peeker->mPatch->serializedSize();
             ninePatchChunk = env->NewByteArray(ninePatchArraySize);
             if (ninePatchChunk == nullptr) {
                 doThrowOOME(env, "Failed to allocate nine patch chunk.");
                 return nullptr;
             }
 
-            env->SetByteArrayRegion(ninePatchChunk, 0, decoder->mPeeker->mPatchSize,
-                                    reinterpret_cast<jbyte*>(decoder->mPeeker->mPatch));
+            env->SetByteArrayRegion(ninePatchChunk, 0, peeker->mPatchSize,
+                                    reinterpret_cast<jbyte*>(peeker->mPatch));
         }
 
-        if (decoder->mPeeker->mHasInsets) {
-            ninePatchInsets = decoder->mPeeker->createNinePatchInsets(env, 1.0f);
+        if (peeker->mHasInsets) {
+            ninePatchInsets = peeker->createNinePatchInsets(env, 1.0f);
             if (ninePatchInsets == nullptr) {
                 doThrowOOME(env, "Failed to allocate nine patch insets.");
                 return nullptr;
@@ -371,58 +388,6 @@
         }
     }
 
-    if (scale || jsubset) {
-        int translateX = 0;
-        int translateY = 0;
-        SkImageInfo scaledInfo;
-        if (jsubset) {
-            SkIRect subset;
-            GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
-
-            translateX = -subset.fLeft;
-            translateY = -subset.fTop;
-            scaledInfo = bitmapInfo.makeWH(subset.width(), subset.height());
-        } else {
-            scaledInfo = bitmapInfo.makeWH(desiredWidth, desiredHeight);
-        }
-        SkBitmap scaledBm;
-        if (!scaledBm.setInfo(scaledInfo)) {
-            doThrowIOE(env, "Failed scaled setInfo");
-            return nullptr;
-        }
-
-        sk_sp<Bitmap> scaledPixelRef;
-        if (allocator == ImageDecoder::kSharedMemory_Allocator) {
-            scaledPixelRef = Bitmap::allocateAshmemBitmap(&scaledBm);
-        } else {
-            scaledPixelRef = Bitmap::allocateHeapBitmap(&scaledBm);
-        }
-        if (!scaledPixelRef) {
-            SkString msg;
-            msg.printf("OOM allocating scaled Bitmap with dimensions %i x %i",
-                    desiredWidth, desiredHeight);
-            doThrowOOME(env, msg.c_str());
-            return nullptr;
-        }
-
-        SkPaint paint;
-        paint.setBlendMode(SkBlendMode::kSrc);
-        paint.setFilterQuality(kLow_SkFilterQuality);  // bilinear filtering
-
-        SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
-        canvas.translate(translateX, translateY);
-        if (scale) {
-            float scaleX = (float) desiredWidth  / decodeInfo.width();
-            float scaleY = (float) desiredHeight / decodeInfo.height();
-            canvas.scale(scaleX, scaleY);
-        }
-
-        canvas.drawBitmap(bm, 0.0f, 0.0f, &paint);
-
-        bm.swap(scaledBm);
-        nativeBitmap = std::move(scaledPixelRef);
-    }
-
     if (jpostProcess) {
         std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
 
@@ -433,12 +398,12 @@
 
         SkAlphaType newAlphaType = bm.alphaType();
         switch (pixelFormat) {
-            case ImageDecoder::kUnknown:
+            case kUnknown:
                 break;
-            case ImageDecoder::kTranslucent:
+            case kTranslucent:
                 newAlphaType = kPremul_SkAlphaType;
                 break;
-            case ImageDecoder::kOpaque:
+            case kOpaque:
                 newAlphaType = kOpaque_SkAlphaType;
                 break;
             default:
@@ -477,7 +442,7 @@
                 return bitmap::createBitmap(env, hwBitmap.release(), bitmapCreateFlags,
                                             ninePatchChunk, ninePatchInsets);
             }
-            if (allocator == ImageDecoder::kHardware_Allocator) {
+            if (allocator == kHardware_Allocator) {
                 doThrowOOME(env, "failed to allocate hardware Bitmap!");
                 return nullptr;
             }
@@ -501,7 +466,7 @@
 static void ImageDecoder_nGetPadding(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                      jobject outPadding) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
-    decoder->mPeeker->getPadding(env, outPadding);
+    reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get())->getPadding(env, outPadding);
 }
 
 static void ImageDecoder_nClose(JNIEnv* /*env*/, jobject /*clazz*/, jlong nativePtr) {
diff --git a/core/jni/android/graphics/ImageDecoder.h b/core/jni/android/graphics/ImageDecoder.h
index fd9827b..8a7fa79 100644
--- a/core/jni/android/graphics/ImageDecoder.h
+++ b/core/jni/android/graphics/ImageDecoder.h
@@ -14,48 +14,12 @@
  * limitations under the License.
  */
 
-#include "NinePatchPeeker.h"
-
 #include <hwui/Canvas.h>
 
 #include <jni.h>
 
-class SkAndroidCodec;
-
-using namespace android;
-
-struct ImageDecoder {
-    // These need to stay in sync with ImageDecoder.java's Allocator constants.
-    enum Allocator {
-        kDefault_Allocator      = 0,
-        kSoftware_Allocator     = 1,
-        kSharedMemory_Allocator = 2,
-        kHardware_Allocator     = 3,
-    };
-
-    // These need to stay in sync with ImageDecoder.java's Error constants.
-    enum Error {
-        kSourceException     = 1,
-        kSourceIncomplete    = 2,
-        kSourceMalformedData = 3,
-    };
-
-    // These need to stay in sync with PixelFormat.java's Format constants.
-    enum PixelFormat {
-        kUnknown     =  0,
-        kTranslucent = -3,
-        kOpaque      = -1,
-    };
-
-    std::unique_ptr<SkAndroidCodec> mCodec;
-    sk_sp<NinePatchPeeker> mPeeker;
-
-    ImageDecoder()
-        :mPeeker(new NinePatchPeeker)
-    {}
-};
-
 // Creates a Java Canvas object from canvas, calls jimageDecoder's PostProcess on it, and then
 // releases the Canvas.
 // Caller needs to check for exceptions.
-jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas);
+jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder,
+                           std::unique_ptr<android::Canvas> canvas);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index f28c422..c4ac89a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -74,6 +74,7 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <bionic/malloc.h>
+#include <bionic/page.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
 #include <cutils/sockets.h>
@@ -1389,9 +1390,14 @@
                               void* data [[maybe_unused]]) {
   // Search for any execute-only segments and mark them read+execute.
   for (int i = 0; i < info->dlpi_phnum; i++) {
-    if ((info->dlpi_phdr[i].p_type == PT_LOAD) && (info->dlpi_phdr[i].p_flags == PF_X)) {
-      mprotect(reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr),
-               info->dlpi_phdr[i].p_memsz, PROT_READ | PROT_EXEC);
+    const auto& phdr = info->dlpi_phdr[i];
+    if ((phdr.p_type == PT_LOAD) && (phdr.p_flags == PF_X)) {
+      auto addr = reinterpret_cast<void*>(info->dlpi_addr + PAGE_START(phdr.p_vaddr));
+      size_t len = PAGE_OFFSET(phdr.p_vaddr) + phdr.p_memsz;
+      if (mprotect(addr, len, PROT_READ | PROT_EXEC) == -1) {
+        ALOGE("mprotect(%p, %zu, PROT_READ | PROT_EXEC) failed: %m", addr, len);
+        return -1;
+      }
     }
   }
   // Return non-zero to exit dl_iterate_phdr.
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 31c19ca..a98d7db 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -566,6 +566,7 @@
     optional LowPowerMode low_power_mode = 70;
 
     optional SettingProto lte_service_forced = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    repeated SettingProto max_error_bytes = 151;
     optional SettingProto mdc_initial_max_retry = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message Mhl {
@@ -1058,5 +1059,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 151;
+    // Next tag = 152;
 }
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index f8c304c..ee5144c 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -152,4 +152,5 @@
   CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES = 125;
   CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126;
   SET_AUTO_TIME = 127;
+  SET_AUTO_TIME_ZONE = 128;
 }
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index e7c2827..272a245 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -63,4 +63,7 @@
     optional uint32 subtree_system_ui_visibility_flags = 28;
     optional uint32 appearance = 29;
     optional uint32 behavior = 30;
+    optional uint32 fit_insets_types = 31;
+    optional uint32 fit_insets_sides = 32;
+    optional bool fit_ignore_visibility = 33;
 }
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 9f296f8f..0c45e45 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -55,6 +55,12 @@
                   android:layout_centerHorizontal="true"/>
     </RelativeLayout>
 
+    <FrameLayout
+        android:id="@+id/content_preview_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone" />
+
     <com.android.internal.widget.ViewPager
         android:id="@+id/profile_pager"
         android:layout_width="match_parent"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a66aa29..89c913b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4183,15 +4183,15 @@
 
     <!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this
          column set. These contacts are stored locally on the device and will not be removed even
-         if an android.account.Account with this name and type exists. A null string will be used
-         if the value is left empty. When this is non-empty then config_rawContactsLocalAccountType
+         if no android.account.Account with this name exists. A null string will be used if the
+         value is left empty. When this is non-empty then config_rawContactsLocalAccountType
          should also be non-empty.  -->
     <string name="config_rawContactsLocalAccountName" translatable="false"></string>
 
     <!-- The default value used for RawContacts.ACCOUNT_TYPE when contacts are inserted without this
          column set. These contacts are stored locally on the device and will not be removed even
-         if an android.account.Account with this name and type exists. A null string will be used
-         if the value is left empty.  When this is non-empty then config_rawContactsLocalAccountName
+         if no android.account.Account with this type exists. A null string will be used if the
+         value is left empty.  When this is non-empty then config_rawContactsLocalAccountName
          should also be non-empty.-->
     <string name="config_rawContactsLocalAccountType" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cc420bd..de1b5ba 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1011,53 +1011,32 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readContacts">read your contacts</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readContacts" product="tablet">Allows the app to read
-      data about your contacts stored on your tablet, including the frequency
-      with which you\'ve called, emailed, or communicated in other ways with
-      specific individuals. Apps will also have access to the accounts on your
-      tablet that have created contacts. This may include accounts created by
-      apps you have installed. This permission allows apps to save your contact
-      data, and malicious apps may share contact data without your
-      knowledge.</string>
+    <string name="permdesc_readContacts" product="tablet">Allows the app to read data about your contacts stored on your tablet.
+      Apps will also have access to the accounts on your tablet that have created contacts.
+      This may include accounts created by apps you have installed.
+      This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readContacts" product="tv">Allows the app to read
-      data about your contacts stored on your Android TV device, including the frequency
-      with which you\'ve called, emailed, or communicated in other ways with
-      specific individuals. Apps will also have access to the accounts on your
-      Android TV device that have created contacts. This may include accounts
-      created by apps you have installed. This permission allows apps to save
-      your contact data, and malicious apps may share contact data without your
-      knowledge.</string>
+    <string name="permdesc_readContacts" product="tv">Allows the app to read data about your contacts stored on your Android TV device.
+      Apps will also have access to the accounts on your Android TV device that have created contacts.
+      This may include accounts created by apps you have installed.
+      This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readContacts" product="default">Allows the app to
-      read data about your contacts stored on your phone, including the
-      frequency with which you\'ve called, emailed, or communicated in other ways
-      with specific individuals. Apps will also have access to the accounts
-      on your phone that have created contacts. This may include accounts
-      created by apps you have installed. This permission allows apps to
-      save your contact data, and malicious apps may share contact data
-      without your knowledge.</string>
+    <string name="permdesc_readContacts" product="default">Allows the app to read data about your contacts stored on your phone.
+      Apps will also have access to the accounts on your phone that have created contacts.
+      This may include accounts created by apps you have installed.
+      This permission allows apps to save your contact data, and malicious apps may share contact data without your knowledge.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeContacts">modify your contacts</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeContacts" product="tablet">Allows the app to
-      modify the data about your contacts stored on your tablet, including the
-      frequency with which you\'ve called, emailed, or communicated in other ways
-      with specific contacts. This permission allows apps to delete contact
-      data.</string>
+    <string name="permdesc_writeContacts" product="tablet">Allows the app to modify the data about your contacts stored on your tablet.
+      This permission allows apps to delete contact data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeContacts" product="tv">Allows the app to
-      modify the data about your contacts stored on your Android TV device, including the
-      frequency with which you\'ve called, emailed, or communicated in other ways
-      with specific contacts. This permission allows apps to delete contact
-      data.</string>
+    <string name="permdesc_writeContacts" product="tv">Allows the app to modify the data about your contacts stored on your Android TV device.
+      This permission allows apps to delete contact data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeContacts" product="default">Allows the app to
-    modify the data about your contacts stored on your phone, including the
-    frequency with which you\'ve called, emailed, or communicated in other ways
-    with specific contacts. This permission allows apps to delete contact
-    data.</string>
+    <string name="permdesc_writeContacts" product="default">Allows the app to modify the data about your contacts stored on your phone.
+      This permission allows apps to delete contact data.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCallLog">read call log</string>
@@ -1102,6 +1081,7 @@
     <string name="permdesc_writeCalendar" product="default">This app can add, remove, or change calendar events on your phone. This app can send messages that may appear to come from calendar owners, or change events without notifying their owners.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the applicatfion to do this. -->
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessLocationExtraCommands">Allows the app to access
@@ -1111,23 +1091,17 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessFineLocation">access precise location only in the foreground</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption.</string>
+    <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. Location services must be turned on and available on your device for the app to be able to use them. This may increase battery consumption.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessCoarseLocation">access approximate location (network-based) only in the foreground</string>
+    <string name="permlab_accessCoarseLocation">access approximate location only in the foreground</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your Android TV device for the app to be able to use them.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="automotive">This app can get your approximate location only when it is in the foreground. These location services must be turned on and available on your car for the app to be able to use them.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string>
+    <string name="permdesc_accessCoarseLocation">This app can get your approximate location only when it is in the foreground. Location services must be turned on and available on your device for the app to be able to use them.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessBackgroundLocation">access location in the background</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessBackgroundLocation">If this is granted additionally to the approximate or precise location access the app can access the location while running in the background.</string>
+    <string name="permdesc_accessBackgroundLocation">This app can access location while running in the background, in addition to foreground location access.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9ad6bad..6956c39 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -248,6 +248,7 @@
   <java-symbol type="id" name="overlay" />
   <java-symbol type="id" name="app_ops" />
   <java-symbol type="id" name="profile_pager" />
+  <java-symbol type="id" name="content_preview_container" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -440,6 +441,7 @@
   <java-symbol type="integer" name="config_multiuserMaxRunningUsers" />
   <java-symbol type="bool" name="config_multiuserDelayUserDataLocking" />
   <java-symbol type="integer" name="config_userTypePackageWhitelistMode"/>
+  <java-symbol type="xml" name="config_user_types" />
   <java-symbol type="integer" name="config_safe_media_volume_index" />
   <java-symbol type="integer" name="config_safe_media_volume_usb_mB" />
   <java-symbol type="integer" name="config_mobile_mtu" />
diff --git a/core/res/res/xml/config_user_types.xml b/core/res/res/xml/config_user_types.xml
new file mode 100644
index 0000000..5fd8a95
--- /dev/null
+++ b/core/res/res/xml/config_user_types.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This xml file allows customization of Android multiuser user types.
+It is parsed by frameworks/base/services/core/java/com/android/server/pm/UserTypeFactory.java.
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++   IMPORTANT NOTE   ++++++++++++++++++++++++++++++++++++++++
+Although device customization is possible here, it is largely untested.
+In particular, although this file allows new profile types to be created, and allows modifying the
+number of managed profiles allowed on the device, the consequences of doing so is untested.
+OEMs are advised to test very carefully any significant customization.
+Further support is planned for later releases.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Pre-defined (AOSP) user types can be customized and new types can be defined. The syntax is the
+same in both cases.
+
+Currently, only profiles (not full or system users) can be freely customized/defined.
+Full users (i.e. non-system, non-profile) users cannot be defined, and the only property of them
+that can be customized are the default-restrictions.
+System users cannot be customized here; their default-restrictions must be set using
+com.android.internal.R.array.config_defaultFirstUserRestrictions.
+
+The following example modifies two AOSP user types (the FULL user android.os.usertype.full.SECONDARY
+and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROFILE user type
+(com.example.profilename):
+
+<user-types>
+    <full-type name="android.os.usertype.full.SECONDARY" >
+        <default-restrictions no_sms="true" />
+    </full-type>
+
+    <profile-type
+        name='android.os.usertype.profile.MANAGED'
+        max-allowed-per-parent='2'
+        icon-badge='@android:drawable/ic_corp_icon_badge_case'
+        badge-plain='@android:drawable/ic_corp_badge_case'
+        badge-no-background='@android:drawable/ic_corp_badge_no_background' >
+        <badge-labels>
+            <item res='@android:string/managed_profile_label_badge' />
+            <item res='@android:string/managed_profile_label_badge_2' />
+        </badge-labels>
+        <badge-colors>
+            <item res='@android:color/profile_badge_1' />
+            <item res='@android:color/profile_badge_2' />
+        </badge-colors>
+        <default-restrictions no_sms="true" no_outgoing_calls="true" />
+    </profile-type>
+
+    <profile-type
+        name="com.example.profilename"
+        max-allowed-per-parent="2" />
+</user-types>
+
+Mandatory attributes:
+    name
+
+Supported optional properties (to be used as shown in the example above) are as follows.
+For profile and full users:
+    default-restrictions (with values defined in UserRestrictionUtils.USER_RESTRICTIONS)
+For profile users only:
+    max-allowed-per-parent
+    icon-badge
+    badge-plain
+    badge-no-background
+    badge-labels
+    badge-colors
+
+See UserTypeFactory.java and UserTypeDetails.java for the meaning (and default values) of these
+fields.
+
+Any property that is specified overwrites the AOSP default. For example, if there is no
+default-restrictions element, then the AOSP defaults for that user type will be used; however, if
+there is a default-restrictions element, then the AOSP default restrictions will be completely
+ignored and will instead obey this configuration.
+
+If this file is updated, the properties of any pre-existing user types will be updated too.
+Note, however, that default-restrictions refers to the restrictions applied at the time of user
+creation; therefore, the active restrictions of any pre-existing users will not be updated.
+
+-->
+<user-types>
+</user-types>
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 9a57847..cf5d079 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -16,13 +16,25 @@
 
 package android.view;
 
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+
 import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
 
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Type;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -55,6 +67,8 @@
 
     @Test
     public void negativeInsets_areSetToZero() throws Exception {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40);
         mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
@@ -65,6 +79,8 @@
 
     @Test
     public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40);
         mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
@@ -75,6 +91,8 @@
 
     @Test
     public void positiveInsets_areLeftAsIs() throws Exception {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40);
         mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
         final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
@@ -83,6 +101,80 @@
         assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40)));
     }
 
+    @Test
+    public void adjustLayoutParamsForInsets_layoutFullscreen() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
+        attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.statusBars());
+    }
+
+    @Test
+    public void adjustLayoutParamsForInsets_layoutInScreen() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
+        attrs.flags = FLAG_LAYOUT_IN_SCREEN;
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.statusBars());
+    }
+
+    @Test
+    public void adjustLayoutParamsForInsets_layoutHideNavigation() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
+        attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.systemBars());
+    }
+
+    @Test
+    public void adjustLayoutParamsForInsets_toast() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_TOAST);
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(Type.systemBars(), attrs.getFitWindowInsetsTypes() & Type.systemBars());
+        assertEquals(true, attrs.getFitIgnoreVisibility());
+    }
+
+    @Test
+    public void adjustLayoutParamsForInsets_systemAlert() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_SYSTEM_ALERT);
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(Type.systemBars(), attrs.getFitWindowInsetsTypes() & Type.systemBars());
+        assertEquals(true, attrs.getFitIgnoreVisibility());
+    }
+
+    @Test
+    public void adjustLayoutParamsForInsets_noAdjust() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
+        final int types = Type.all();
+        final int sides = Side.TOP | Side.LEFT;
+        final boolean fitMaxInsets = true;
+        attrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        attrs.setFitWindowInsetsTypes(types);
+        attrs.setFitWindowInsetsSides(sides);
+        attrs.setFitIgnoreVisibility(fitMaxInsets);
+        ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
+
+        assertEquals(types, attrs.getFitWindowInsetsTypes());
+        assertEquals(sides, attrs.getFitWindowInsetsSides());
+        assertEquals(fitMaxInsets, attrs.getFitIgnoreVisibility());
+    }
+
     private static class ViewRootImplAccessor {
 
         private final ViewRootImpl mViewRootImpl;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 6bce651..0d5db6d 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -436,6 +436,22 @@
     }
 
     @Test
+    public void windowsChangedWithWindowsChangeA11yFocusedEvent_dontClearCache() {
+        AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+        mAccessibilityCache.add(nodeInfo);
+        AccessibilityEvent event = new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+        event.setWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED);
+        mAccessibilityCache.onAccessibilityEvent(event);
+        AccessibilityNodeInfo cachedNode = mAccessibilityCache.getNode(WINDOW_ID_1,
+                nodeInfo.getSourceNodeId());
+        try {
+            assertNotNull(cachedNode);
+        } finally {
+            nodeInfo.recycle();
+        }
+    }
+
+    @Test
     public void subTreeChangeEvent_clearsNodeAndChild() {
         AccessibilityEvent event = AccessibilityEvent
                 .obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index a2e0095..2a10443 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -48,7 +48,7 @@
     private UsageStatsManager mUsm;
 
     ChooserListAdapter getAdapter() {
-        return mChooserMultiProfilePagerAdapter.getCurrentListAdapter();
+        return mChooserMultiProfilePagerAdapter.getActiveListAdapter();
     }
 
     boolean getIsSelected() { return mIsSuccessfullySelected; }
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 93357af..c5d2cfa 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -46,7 +46,7 @@
     }
 
     ResolverWrapperAdapter getAdapter() {
-        return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getCurrentListAdapter();
+        return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getActiveListAdapter();
     }
 
     @Override
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 43f65e3..183c04e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -120,7 +120,7 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.storagemanager",
-    product_specific: true,
+    system_ext_specific: true,
     sub_dir: "permissions",
     src: "com.android.storagemanager.xml",
     filename_from_src: true,
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index eff353c..3060476 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -7,12 +7,6 @@
       "group": "WM_DEBUG_KEEP_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-2138637148": {
-      "message": "Clearing focused app, displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/ActivityDisplay.java"
-    },
     "-2127842445": {
       "message": "Clearing startingData for token=%s",
       "level": "VERBOSE",
@@ -709,6 +703,12 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-603199586": {
+      "message": "Clearing focused app, displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-583031528": {
       "message": "%s",
       "level": "INFO",
@@ -1315,6 +1315,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "584499099": {
+      "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "585096182": {
       "message": "SURFACE isColorSpaceAgnostic=%b: %s",
       "level": "INFO",
@@ -1513,12 +1519,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
-    "917739349": {
-      "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/ActivityDisplay.java"
-    },
     "954470154": {
       "message": "FORCED DISPLAY SCALING DISABLED",
       "level": "INFO",
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 94499ce..8a7b623 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -204,10 +204,7 @@
                     break;
                 }
                 case USE_INDIVIDUAL_ATTESTATION: {
-                    //TODO: Add the Keymaster tag for requesting the use of individual
-                    //attestation certificate, which should be
-                    //KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION
-                    attestArgs.addBoolean(720);
+                    attestArgs.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
                     break;
                 }
                 default:
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index f670cf9..d945fc4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -176,6 +176,7 @@
         "hwui/AnimatedImageThread.cpp",
         "hwui/Bitmap.cpp",
         "hwui/Canvas.cpp",
+        "hwui/ImageDecoder.cpp",
         "hwui/MinikinSkia.cpp",
         "hwui/MinikinUtils.cpp",
         "hwui/PaintImpl.cpp",
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 2ba6fbe..f4149b9 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -44,9 +44,7 @@
 
 namespace android {
 
-// returns true if rowBytes * height can be represented by a positive int32_t value
-// and places that value in size.
-static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
+bool Bitmap::computeAllocationSize(size_t rowBytes, int height, size_t* size) {
     return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
            !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
            *size <= std::numeric_limits<int32_t>::max();
@@ -66,7 +64,7 @@
     // we must respect the rowBytes value already set on the bitmap instead of
     // attempting to compute our own.
     const size_t rowBytes = bitmap->rowBytes();
-    if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
+    if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) {
         return nullptr;
     }
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 00733c6..1cda046 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -138,6 +138,10 @@
         return mPalette;
     }
 
+  // returns true if rowBytes * height can be represented by a positive int32_t value
+  // and places that value in size.
+  static bool computeAllocationSize(size_t rowBytes, int height, size_t* size);
+
 private:
     static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
     static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
new file mode 100644
index 0000000..4f2027d
--- /dev/null
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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 "ImageDecoder.h"
+
+#include <hwui/Bitmap.h>
+
+#include <SkAndroidCodec.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+
+using namespace android;
+
+ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker)
+    : mCodec(std::move(codec))
+    , mPeeker(std::move(peeker))
+    , mTargetSize(mCodec->getInfo().dimensions())
+    , mDecodeSize(mTargetSize)
+    , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
+    , mOutAlphaType(mCodec->getInfo().isOpaque() ?
+                    kOpaque_SkAlphaType : kPremul_SkAlphaType)
+    , mOutColorSpace(mCodec->getInfo().refColorSpace())
+    , mSampleSize(1)
+{
+}
+
+bool ImageDecoder::setTargetSize(int width, int height) {
+    if (width <= 0 || height <= 0) {
+        return false;
+    }
+
+    auto info = SkImageInfo::Make(width, height, mOutColorType, mOutAlphaType);
+    size_t rowBytes = info.minRowBytes();
+    if (rowBytes == 0) {
+        // This would have overflowed.
+        return false;
+    }
+
+    size_t pixelMemorySize;
+    if (!Bitmap::computeAllocationSize(rowBytes, height, &pixelMemorySize)) {
+        return false;
+    }
+
+    if (mCropRect) {
+        if (mCropRect->right() > width || mCropRect->bottom() > height) {
+            return false;
+        }
+    }
+
+    SkISize targetSize = { width, height }, decodeSize = targetSize;
+    int sampleSize = mCodec->computeSampleSize(&decodeSize);
+
+    if (decodeSize != targetSize && mOutAlphaType == kUnpremul_SkAlphaType
+            && !mCodec->getInfo().isOpaque()) {
+        return false;
+    }
+
+    mTargetSize = targetSize;
+    mDecodeSize = decodeSize;
+    mSampleSize = sampleSize;
+    return true;
+}
+
+bool ImageDecoder::setCropRect(const SkIRect* crop) {
+    if (!crop) {
+        mCropRect.reset();
+        return true;
+    }
+
+    if (crop->left() >= crop->right() || crop->top() >= crop->bottom()) {
+        return false;
+    }
+
+    const auto& size = mTargetSize;
+    if (crop->left() < 0 || crop->top() < 0
+            || crop->right() > size.width() || crop->bottom() > size.height()) {
+      return false;
+    }
+
+    mCropRect.emplace(*crop);
+    return true;
+}
+
+bool ImageDecoder::setOutColorType(SkColorType colorType) {
+    switch (colorType) {
+        case kRGB_565_SkColorType:
+            if (!opaque()) {
+                return false;
+            }
+            break;
+        case kGray_8_SkColorType:
+            if (!gray()) {
+                return false;
+            }
+            mOutColorSpace = nullptr;
+            break;
+        case kN32_SkColorType:
+            break;
+        case kRGBA_F16_SkColorType:
+            break;
+        default:
+            return false;
+    }
+
+    mOutColorType = colorType;
+    return true;
+}
+
+bool ImageDecoder::setOutAlphaType(SkAlphaType alpha) {
+    switch (alpha) {
+        case kOpaque_SkAlphaType:
+            return opaque();
+        case kPremul_SkAlphaType:
+            if (opaque()) {
+                // Opaque can be treated as premul.
+                return true;
+            }
+            break;
+        case kUnpremul_SkAlphaType:
+            if (opaque()) {
+                // Opaque can be treated as unpremul.
+                return true;
+            }
+            if (mDecodeSize != mTargetSize) {
+                return false;
+            }
+            break;
+        default:
+            return false;
+    }
+    mOutAlphaType = alpha;
+    return true;
+}
+
+void ImageDecoder::setOutColorSpace(sk_sp<SkColorSpace> colorSpace) {
+    mOutColorSpace = std::move(colorSpace);
+}
+
+SkImageInfo ImageDecoder::getOutputInfo() const {
+    SkISize size = mCropRect ? mCropRect->size() : mTargetSize;
+    return SkImageInfo::Make(size, mOutColorType, mOutAlphaType, mOutColorSpace);
+}
+
+bool ImageDecoder::opaque() const {
+    return mOutAlphaType == kOpaque_SkAlphaType;
+}
+
+bool ImageDecoder::gray() const {
+    return mCodec->getInfo().colorType() == kGray_8_SkColorType;
+}
+
+SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
+    void* decodePixels = pixels;
+    size_t decodeRowBytes = rowBytes;
+    auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, mOutAlphaType, mOutColorSpace);
+    // Used if we need a temporary before scaling or subsetting.
+    // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
+    SkBitmap tmp;
+    const bool scale = mDecodeSize != mTargetSize;
+    if (scale || mCropRect) {
+        if (!tmp.setInfo(decodeInfo)) {
+            return SkCodec::kInternalError;
+        }
+        if (!Bitmap::allocateHeapBitmap(&tmp)) {
+            return SkCodec::kInternalError;
+        }
+        decodePixels = tmp.getPixels();
+        decodeRowBytes = tmp.rowBytes();
+    }
+
+    SkAndroidCodec::AndroidOptions options;
+    options.fSampleSize = mSampleSize;
+    auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &options);
+
+    if (scale || mCropRect) {
+        SkBitmap scaledBm;
+        if (!scaledBm.installPixels(getOutputInfo(), pixels, rowBytes)) {
+            return SkCodec::kInternalError;
+        }
+
+        SkPaint paint;
+        paint.setBlendMode(SkBlendMode::kSrc);
+        paint.setFilterQuality(kLow_SkFilterQuality);  // bilinear filtering
+
+        SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
+        if (mCropRect) {
+            canvas.translate(-mCropRect->fLeft, -mCropRect->fTop);
+        }
+        if (scale) {
+            float scaleX = (float) mTargetSize.width()  / mDecodeSize.width();
+            float scaleY = (float) mTargetSize.height() / mDecodeSize.height();
+            canvas.scale(scaleX, scaleY);
+        }
+
+        canvas.drawBitmap(tmp, 0.0f, 0.0f, &paint);
+    }
+
+    return result;
+}
+
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
new file mode 100644
index 0000000..b956f4a
--- /dev/null
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <SkCodec.h>
+#include <SkImageInfo.h>
+#include <SkPngChunkReader.h>
+#include <SkRect.h>
+#include <SkSize.h>
+#include <cutils/compiler.h>
+
+#include <optional>
+
+class SkAndroidCodec;
+
+namespace android {
+
+class ANDROID_API ImageDecoder {
+public:
+    std::unique_ptr<SkAndroidCodec> mCodec;
+    sk_sp<SkPngChunkReader> mPeeker;
+
+    ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,
+                 sk_sp<SkPngChunkReader> peeker = nullptr);
+
+    bool setTargetSize(int width, int height);
+    bool setCropRect(const SkIRect*);
+
+    bool setOutColorType(SkColorType outColorType);
+
+    bool setOutAlphaType(SkAlphaType outAlphaType);
+
+    void setOutColorSpace(sk_sp<SkColorSpace> cs);
+
+    // The size is the final size after scaling and cropping.
+    SkImageInfo getOutputInfo() const;
+    SkColorType getOutColorType() const { return mOutColorType; }
+    SkAlphaType getOutAlphaType() const { return mOutAlphaType; }
+
+    bool opaque() const;
+    bool gray() const;
+
+    SkCodec::Result decode(void* pixels, size_t rowBytes);
+
+private:
+    SkISize mTargetSize;
+    SkISize mDecodeSize;
+    SkColorType mOutColorType;
+    SkAlphaType mOutAlphaType;
+    sk_sp<SkColorSpace> mOutColorSpace;
+    int mSampleSize;
+    std::optional<SkIRect> mCropRect;
+
+    ImageDecoder(const ImageDecoder&) = delete;
+    ImageDecoder& operator=(const ImageDecoder&) = delete;
+};
+
+} // namespace android
diff --git a/media/Android.bp b/media/Android.bp
index 1912930..e2bdad1 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -82,7 +82,7 @@
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
-    "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi "
+    "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) "
 
 droidstubs {
     name: "updatable-media-stubs",
diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java
index b83f445..ac66d1b 100644
--- a/media/apex/java/android/media/MediaParser.java
+++ b/media/apex/java/android/media/MediaParser.java
@@ -102,7 +102,8 @@
  *     public void onSeekMap(int i, @NonNull MediaFormat mediaFormat) { \/* Do nothing. *\/ }
  *
  *     \@Override
- *     public void onFormat(int i, @NonNull MediaFormat mediaFormat) {
+ *     public void onTrackData(int i, @NonNull TrackData trackData) {
+ *       MediaFormat mediaFormat = trackData.mediaFormat;
  *       if (videoTrackIndex == -1 && mediaFormat
  *           .getString(MediaFormat.KEY_MIME, \/* defaultValue= *\/ "").startsWith("video/")) {
  *         videoTrackIndex = i;
@@ -200,6 +201,24 @@
         }
     }
 
+    /** Holds information associated with a track. */
+    public static final class TrackData {
+
+        /** Holds {@link MediaFormat} information for the track. */
+        @NonNull public final MediaFormat mediaFormat;
+
+        /**
+         * Holds {@link DrmInitData} necessary to acquire keys associated with the track, or null if
+         * the track has no encryption data.
+         */
+        @Nullable public final DrmInitData drmInitData;
+
+        private TrackData(MediaFormat mediaFormat, DrmInitData drmInitData) {
+            this.mediaFormat = mediaFormat;
+            this.drmInitData = drmInitData;
+        }
+    }
+
     /** Defines a seek point in a media stream. */
     public static final class SeekPoint {
 
@@ -308,12 +327,12 @@
         void onTracksFound(int numberOfTracks);
 
         /**
-         * Called when the {@link MediaFormat} of the track is extracted from the stream.
+         * Called when new {@link TrackData} is extracted from the stream.
          *
-         * @param trackIndex The index of the track for which the {@link MediaFormat} was found.
-         * @param format The extracted {@link MediaFormat}.
+         * @param trackIndex The index of the track for which the {@link TrackData} was extracted.
+         * @param trackData The extracted {@link TrackData}.
          */
-        void onFormat(int trackIndex, @NonNull MediaFormat format);
+        void onTrackData(int trackIndex, @NonNull TrackData trackData);
 
         /**
          * Called to write sample data to the output.
@@ -674,7 +693,10 @@
 
         @Override
         public void format(Format format) {
-            mOutputConsumer.onFormat(mTrackIndex, toMediaFormat(format));
+            mOutputConsumer.onTrackData(
+                    mTrackIndex,
+                    new TrackData(
+                            toMediaFormat(format), toFrameworkDrmInitData(format.drmInitData)));
         }
 
         @Override
@@ -846,6 +868,12 @@
         return 0;
     }
 
+    private static DrmInitData toFrameworkDrmInitData(
+            com.google.android.exoplayer2.drm.DrmInitData drmInitData) {
+        // TODO: Implement.
+        return null;
+    }
+
     private static MediaCodec.CryptoInfo toCryptoInfo(TrackOutput.CryptoData encryptionData) {
         // TODO: Implement.
         return null;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 066bf25..df799fd 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -1288,7 +1289,8 @@
      * </ul>
      */
     public static int getPlatformType(Context context) {
-        if (context.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+        if (((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
+                .isVoiceCapable()) {
             return PLATFORM_VOICE;
         } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
             return PLATFORM_TELEVISION;
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
old mode 100644
new mode 100755
index bd05184..f90c504
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -38,4 +38,5 @@
     void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
     void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
     void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+    void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
 }
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
old mode 100644
new mode 100755
index ff69779..5c11ed9b
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -173,6 +173,12 @@
                 mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT,
                         deviceInfo).sendToTarget();
             }
+
+            @Override
+            public void notifyHdmiDeviceUpdated(HdmiDeviceInfo deviceInfo) {
+                mServiceHandler.obtainMessage(ServiceHandler.DO_UPDATE_HDMI_INPUT,
+                        deviceInfo).sendToTarget();
+            }
         };
     }
 
@@ -257,6 +263,24 @@
         return null;
     }
 
+    /**
+     * Called when {@code deviceInfo} is updated.
+     *
+     * <p>The changes are usually cuased by the corresponding HDMI-CEC logical device.
+     *
+     * <p>The default behavior ignores all changes.
+     *
+     * <p>The TV input service responsible for {@code deviceInfo} can update the {@link TvInputInfo}
+     * object based on the updated {@code deviceInfo} (e.g. update the label based on the preferred
+     * device OSD name).
+     *
+     * @param deviceInfo the updated {@link HdmiDeviceInfo} object.
+     * @hide
+     */
+    @SystemApi
+    public void onHdmiDeviceUpdated(@NonNull HdmiDeviceInfo deviceInfo) {
+    }
+
     private boolean isPassthroughInput(String inputId) {
         if (mTvInputManager == null) {
             mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
@@ -1962,6 +1986,7 @@
         private static final int DO_REMOVE_HARDWARE_INPUT = 5;
         private static final int DO_ADD_HDMI_INPUT = 6;
         private static final int DO_REMOVE_HDMI_INPUT = 7;
+        private static final int DO_UPDATE_HDMI_INPUT = 8;
 
         private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) {
             int n = mCallbacks.beginBroadcast();
@@ -2131,6 +2156,11 @@
                     }
                     return;
                 }
+                case DO_UPDATE_HDMI_INPUT: {
+                    HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
+                    onHdmiDeviceUpdated(deviceInfo);
+                    return;
+                }
                 default: {
                     Log.w(TAG, "Unhandled message code: " + msg.what);
                     return;
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 08ab492..998d2b9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -278,6 +278,7 @@
             leftlp.windowAnimations = 0;
             leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
             leftlp.gravity = Gravity.LEFT;
+            leftlp.setFitWindowInsetsTypes(0 /* types */);
             mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
         }
         if (mRightNavigationBarWindow != null) {
@@ -295,6 +296,7 @@
             rightlp.windowAnimations = 0;
             rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
             rightlp.gravity = Gravity.RIGHT;
+            rightlp.setFitWindowInsetsTypes(0 /* types */);
             mWindowManager.addView(mRightNavigationBarWindow, rightlp);
         }
     }
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 0d6701d..fbc03c0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -563,7 +563,12 @@
         mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
 
         mNotificationDataManager = new NotificationDataManager();
-        mNotificationDataManager.setOnUnseenCountUpdateListener(this::onUnseenCountUpdate);
+
+        mNotificationDataManager.setOnUnseenCountUpdateListener(() -> {
+            if (mNotificationDataManager != null) {
+                onUseenCountUpdate(mNotificationDataManager.getUnseenNotificationCount());
+            }
+        });
 
         mEnableHeadsUpNotificationWhenNotificationShadeOpen = mContext.getResources().getBoolean(
                 R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
@@ -685,15 +690,13 @@
     }
 
     /**
-     * This method is called whenever there is an update to the number of unseen notifications.
-     * This method can be extended by OEMs to customize the desired logic.
+     * This method is automatically called whenever there is an update to the number of unseen
+     * notifications. This method can be extended by OEMs to customize the desired logic.
      */
-    protected void onUnseenCountUpdate() {
-        if (mNotificationDataManager != null) {
-            boolean hasUnseen = mNotificationDataManager.getUnseenNotificationCount() > 0;
-            mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
-                    mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
-        }
+    protected void onUseenCountUpdate(int unseenNotificationCount) {
+        boolean hasUnseen = unseenNotificationCount > 0;
+        mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
+                mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
index ec46433..2d57be1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -240,7 +240,7 @@
     }
 
     private WindowManager.LayoutParams createLayoutParams() {
-        return new WindowManager.LayoutParams(
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
                 WindowManager.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
@@ -249,6 +249,8 @@
                         | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
                 PixelFormat.TRANSLUCENT
         );
+        attrs.setFitWindowInsetsTypes(0 /* types */);
+        return attrs;
     }
 
     private void logd(String message) {
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/Android.bp b/packages/Incremental/NativeAdbDataLoader/jni/Android.bp
index 8f28101..0fcfd28 100644
--- a/packages/Incremental/NativeAdbDataLoader/jni/Android.bp
+++ b/packages/Incremental/NativeAdbDataLoader/jni/Android.bp
@@ -33,6 +33,5 @@
         "liblog",
         "libnativehelper",
         "libutils",
-        "libincremental_aidl-cpp",
     ],
 }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 39c55fd..9b4a6d6 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -140,8 +140,6 @@
         <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
         <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
         <item>LDAC</item>
-        <item>Enable Optional Codecs</item>
-        <item>Disable Optional Codecs</item>
     </string-array>
 
     <!-- Values for Bluetooth Audio Codec selection preference. -->
@@ -152,8 +150,6 @@
         <item>2</item>
         <item>3</item>
         <item>4</item>
-        <item>5</item>
-        <item>6</item>
     </string-array>
 
     <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
@@ -164,8 +160,6 @@
         <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
         <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
         <item>LDAC</item>
-        <item>Enable Optional Codecs</item>
-        <item>Disable Optional Codecs</item>
     </string-array>
 
     <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index e660e43..d3f9cd4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -116,7 +116,7 @@
         }
         return new Pair<>(
                 getBluetoothDrawable(context,
-                        com.android.internal.R.drawable.ic_settings_bluetooth),
+                        com.android.internal.R.drawable.ic_settings_bluetooth).mutate(),
                 context.getString(R.string.bluetooth_talkback_bluetooth));
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 5cf44e1..a82231a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -23,6 +23,9 @@
 import android.text.TextUtils;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.ArrayList;
@@ -132,34 +135,44 @@
         return ((Instrumentable) object).getMetricsCategory();
     }
 
-    public void logDashboardStartIntent(Context context, Intent intent,
-            int sourceMetricsCategory) {
+    /**
+     * Logs an event when the preference is clicked.
+     *
+     * @return true if the preference is loggable, otherwise false
+     */
+    public boolean logClickedPreference(@NonNull Preference preference, int sourceMetricsCategory) {
+        if (preference == null) {
+            return false;
+        }
+        return logSettingsTileClick(preference.getKey(), sourceMetricsCategory)
+                || logStartedIntent(preference.getIntent(), sourceMetricsCategory)
+                || logSettingsTileClick(preference.getFragment(), sourceMetricsCategory);
+    }
+
+    /**
+     * Logs an event when the intent is started.
+     *
+     * @return true if the intent is loggable, otherwise false
+     */
+    public boolean logStartedIntent(Intent intent, int sourceMetricsCategory) {
         if (intent == null) {
-            return;
+            return false;
         }
         final ComponentName cn = intent.getComponent();
-        if (cn == null) {
-            final String action = intent.getAction();
-            if (TextUtils.isEmpty(action)) {
-                // Not loggable
-                return;
-            }
-            action(sourceMetricsCategory,
-                    MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
-                    SettingsEnums.PAGE_UNKNOWN,
-                    action,
-                    0);
-            return;
-        } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
-            // Going to a Setting internal page, skip click logging in favor of page's own
-            // visibility logging.
-            return;
+        return logSettingsTileClick(cn != null ? cn.flattenToString() : intent.getAction(),
+                sourceMetricsCategory);
+    }
+
+    private boolean logSettingsTileClick(String logKey, int sourceMetricsCategory) {
+        if (TextUtils.isEmpty(logKey)) {
+            // Not loggable
+            return false;
         }
         action(sourceMetricsCategory,
                 MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
                 SettingsEnums.PAGE_UNKNOWN,
-                cn.flattenToString(),
+                logKey,
                 0);
+        return true;
     }
-
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 49e214b..443543b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1395,7 +1395,7 @@
         mConfig = new WifiConfiguration();
         mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
 
-        if (security == SECURITY_NONE || !getWifiManager().isEasyConnectSupported()) {
+        if (security == SECURITY_NONE) {
             mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
         } else {
             mConfig.allowedKeyManagement.set(KeyMgmt.OWE);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 2a70506..3818057 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -1713,4 +1713,21 @@
                 .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
                 .build();
     }
+
+    @Test
+    public void testGenerateOpenNetworkConfig_oweNotSupported_shouldGetCorrectSecurity() {
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        AccessPoint oweAccessPoint = new TestAccessPointBuilder(mMockContext)
+                .setSecurity(AccessPoint.SECURITY_OWE).build();
+        AccessPoint noneAccessPoint = new TestAccessPointBuilder(mMockContext)
+                .setSecurity(AccessPoint.SECURITY_NONE).build();
+
+        oweAccessPoint.generateOpenNetworkConfig();
+        noneAccessPoint.generateOpenNetworkConfig();
+
+        assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isFalse();
+        assertThat(oweAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isTrue();
+        assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.NONE)).isTrue();
+        assertThat(noneAccessPoint.getConfig().allowedKeyManagement.get(KeyMgmt.OWE)).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index 8a0ae91..ed0857c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -26,6 +26,8 @@
 import android.content.Context;
 import android.content.Intent;
 
+import androidx.preference.Preference;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import org.junit.Before;
@@ -60,19 +62,42 @@
     }
 
     @Test
-    public void logDashboardStartIntent_intentEmpty_shouldNotLog() {
-        mProvider.logDashboardStartIntent(mContext, null /* intent */,
+    public void logClickedPreference_preferenceEmpty_shouldNotLog() {
+        final boolean loggable = mProvider.logClickedPreference(null /* preference */,
                 MetricsEvent.SETTINGS_GESTURES);
 
+        assertThat(loggable).isFalse();
         verifyNoMoreInteractions(mLogWriter);
     }
 
     @Test
-    public void logDashboardStartIntent_intentHasNoComponent_shouldLog() {
+    public void logClickedPreference_preferenceHasKey_shouldLog() {
+        final String key = "abc";
+        final Preference preference = new Preference(mContext);
+        preference.setKey(key);
+
+        final boolean loggable = mProvider.logClickedPreference(preference,
+                MetricsEvent.SETTINGS_GESTURES);
+
+        assertThat(loggable).isTrue();
+        verify(mLogWriter).action(
+                MetricsEvent.SETTINGS_GESTURES,
+                MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+                SettingsEnums.PAGE_UNKNOWN,
+                key,
+                0);
+    }
+
+    @Test
+    public void logClickedPreference_preferenceHasIntent_shouldLog() {
+        final Preference preference = new Preference(mContext);
         final Intent intent = new Intent(Intent.ACTION_ASSIST);
+        preference.setIntent(intent);
 
-        mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+        final boolean loggable = mProvider.logClickedPreference(preference,
+                MetricsEvent.SETTINGS_GESTURES);
 
+        assertThat(loggable).isTrue();
         verify(mLogWriter).action(
                 MetricsEvent.SETTINGS_GESTURES,
                 MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
@@ -82,11 +107,54 @@
     }
 
     @Test
-    public void logDashboardStartIntent_intentIsExternal_shouldLog() {
+    public void logClickedPreference_preferenceHasFragment_shouldLog() {
+        final Preference preference = new Preference(mContext);
+        final String fragment = "com.android.settings.tts.TextToSpeechSettings";
+        preference.setFragment(fragment);
+
+        final boolean loggable = mProvider.logClickedPreference(preference,
+                MetricsEvent.SETTINGS_GESTURES);
+
+        assertThat(loggable).isTrue();
+        verify(mLogWriter).action(
+                MetricsEvent.SETTINGS_GESTURES,
+                MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+                SettingsEnums.PAGE_UNKNOWN,
+                fragment,
+                0);
+    }
+
+    @Test
+    public void logStartedIntent_intentEmpty_shouldNotLog() {
+        final boolean loggable = mProvider.logStartedIntent(null /* intent */,
+                MetricsEvent.SETTINGS_GESTURES);
+
+        assertThat(loggable).isFalse();
+        verifyNoMoreInteractions(mLogWriter);
+    }
+
+    @Test
+    public void logStartedIntent_intentHasNoComponent_shouldLog() {
+        final Intent intent = new Intent(Intent.ACTION_ASSIST);
+
+        final boolean loggable = mProvider.logStartedIntent(intent, MetricsEvent.SETTINGS_GESTURES);
+
+        assertThat(loggable).isTrue();
+        verify(mLogWriter).action(
+                MetricsEvent.SETTINGS_GESTURES,
+                MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+                SettingsEnums.PAGE_UNKNOWN,
+                Intent.ACTION_ASSIST,
+                0);
+    }
+
+    @Test
+    public void logStartedIntent_intentIsExternal_shouldLog() {
         final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
 
-        mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+        final boolean loggable = mProvider.logStartedIntent(intent, MetricsEvent.SETTINGS_GESTURES);
 
+        assertThat(loggable).isTrue();
         verify(mLogWriter).action(
                 MetricsEvent.SETTINGS_GESTURES,
                 MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
diff --git a/packages/SettingsProvider/res/values-af/strings.xml b/packages/SettingsProvider/res/values-af/strings.xml
index 2c45484..8c2f8b3 100644
--- a/packages/SettingsProvider/res/values-af/strings.xml
+++ b/packages/SettingsProvider/res/values-af/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Instellingsberging"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Veranderings aan jou warmkolinstellings"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Jou warmkolband het verander."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Hierdie toestel steun nie jou voorkeur vir net 5 GHz nie. Hierdie toestel sal pleks daarvan die 5 GHz-band gebruik wanneer dit beskikbaar is."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-am/strings.xml b/packages/SettingsProvider/res/values-am/strings.xml
index 0630560..640301a 100644
--- a/packages/SettingsProvider/res/values-am/strings.xml
+++ b/packages/SettingsProvider/res/values-am/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"የቅንብሮች ማከማቻ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"በእርስዎ ሆትስፖት ቅንብሮች ላይ ለውጦች"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"የእርስዎ ሆትስፖት ባንድ ተለውጧል።"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ይህ መሣሪያ የእርስዎን ምርጫ ለ5GHz ብቻ አይደግፍም። በምትኩ፣ ይህ መሣሪያ ሲገኝ 5GHz ባንድ ይጠቀማል።"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ar/strings.xml b/packages/SettingsProvider/res/values-ar/strings.xml
index 19306a6..2675839 100644
--- a/packages/SettingsProvider/res/values-ar/strings.xml
+++ b/packages/SettingsProvider/res/values-ar/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"تخزين الإعدادات"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"التغييرات التي طرأت على إعدادات نقطة الاتصال"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"تمّ تغيير نطاق نقطة الاتصال الخاصة بك."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"لا يتوافق هذا الجهاز مع إعدادك المفضّل الخاص باستخدام النطاق 5 غيغاهرتز فقط. وسيستخدم الجهاز بدلاً من ذلك النطاق 5 غيغاهرتز عندما يكون متاحًا."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-as/strings.xml b/packages/SettingsProvider/res/values-as/strings.xml
index 13b90d6..b70146a 100644
--- a/packages/SettingsProvider/res/values-as/strings.xml
+++ b/packages/SettingsProvider/res/values-as/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ছেটিংছসমূহৰ সঞ্চয়াগাৰ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"আপোনাৰ হটস্পট ছেটিংসমূহত হোৱা সালসলনিসমূহ"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হৈছে।"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"আপোনাৰ কেৱল ৫ গিগাহাৰ্টজৰ প্ৰতি অগ্ৰাধিকাৰ এই ডিভাচইচটোৱে সমৰ্থন নকৰে। ইয়াৰ পৰিৱৰ্তে, ডিভাচইচটোৱে যেতিয়া ৫ গিগাহাৰ্টজ বেণ্ড উপলব্ধ হ’ব তেতিয়া তাক ব্যৱহাৰ কৰিব।"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-az/strings.xml b/packages/SettingsProvider/res/values-az/strings.xml
index 4737a1e..8b4f75b 100644
--- a/packages/SettingsProvider/res/values-az/strings.xml
+++ b/packages/SettingsProvider/res/values-az/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Ayarlar Deposu"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Hotspot ayarlarınızda dəyişiklik"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Hotspot diapazonu dəyişib."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Bu cihaz yalnız 5GHz üçün tərcihinizi dəstəkləmir. Əvəzində, əlçatan olduqda bu cihaz 5GHz diapazonundan istifadə edəcək."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml
index 032dbc5..9c3a00e 100644
--- a/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Podešavanja skladišta"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Promene podešavanja za hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Opseg hotspota je promenjen."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Ovaj uređaj ne podržava podešavanje samo za 5 GHz. Uređaj će koristiti opseg od 5 GHz kada bude dostupan."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-be/strings.xml b/packages/SettingsProvider/res/values-be/strings.xml
index 60bdb2d..0e098e7 100644
--- a/packages/SettingsProvider/res/values-be/strings.xml
+++ b/packages/SettingsProvider/res/values-be/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Сховішча налад"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Змяненні ў наладах хот-спота"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Частата хот-спота змянілася."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Прылада не можа працаваць толькі на частаце 5 ГГц. Гэта частата будзе выкарыстоўвацца, калі гэта магчыма."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-bg/strings.xml b/packages/SettingsProvider/res/values-bg/strings.xml
index c3a994b..30526f2 100644
--- a/packages/SettingsProvider/res/values-bg/strings.xml
+++ b/packages/SettingsProvider/res/values-bg/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Настройки за хранилище"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Промени в настройките ви за точка за достъп"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Честотната лента на точката ви за достъп е променена."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Това устройство не поддържа предпочитанието ви за използване само на честотната лента от 5 ГХц. Вместо това то ще я ползва, когато е възможно."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-bn/strings.xml b/packages/SettingsProvider/res/values-bn/strings.xml
index 71ee99b..8fc6bbb 100644
--- a/packages/SettingsProvider/res/values-bn/strings.xml
+++ b/packages/SettingsProvider/res/values-bn/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"সেটিংস স্টোরেজ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"আপনার হটস্পট সেটিংসে করা পরিবর্তনগুলি"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"আপনার হটস্পট ব্যান্ড পরিবর্তন করা হয়েছে।"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"এই ডিভাইসটি শুধুমাত্র 5GHz এর জন্য আপনার পছন্দ সমর্থন করে না। পরিবর্তে, এই ডিভাইসটি 5GHz ব্যান্ড ব্যবহার করবে।"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-bs/strings.xml b/packages/SettingsProvider/res/values-bs/strings.xml
index 09d4c68..ddacb32 100644
--- a/packages/SettingsProvider/res/values-bs/strings.xml
+++ b/packages/SettingsProvider/res/values-bs/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Postavke za pohranu podataka"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Promjene postavki pristupne tačke"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Opseg pristupne tačke je promijenjen."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Ovaj uređaj ne podržava vašu postavku za mreže od isključivo 5 GHz. Uređaj će koristiti opseg of 5 GHz kada bude dostupan."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ca/strings.xml b/packages/SettingsProvider/res/values-ca/strings.xml
index ee6b51e..0c2ad73 100644
--- a/packages/SettingsProvider/res/values-ca/strings.xml
+++ b/packages/SettingsProvider/res/values-ca/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Configuració de l\'emmagatzematge"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Canvis en la configuració del punt d\'accés Wi‑Fi"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Ha canviat la teva banda del punt d\'accés Wi‑Fi."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Aquest dispositiu no admet utilitzar exclusivament una banda de 5 GHz. El dispositiu utilitzarà una banda de 5 GHz quan estigui disponible."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-cs/strings.xml b/packages/SettingsProvider/res/values-cs/strings.xml
index f134e05..ab474b1 100644
--- a/packages/SettingsProvider/res/values-cs/strings.xml
+++ b/packages/SettingsProvider/res/values-cs/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Paměť pro nastavení"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Změny nastavení hotspotu"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Pásmo hotspotu se změnilo."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Toto zařízení nepodporuje vaše nastavení jen 5GHz pásma. Zařízení použije pásmo 5 GHz, jen když bude dostupné."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-da/strings.xml b/packages/SettingsProvider/res/values-da/strings.xml
index 99988a5..719614c 100644
--- a/packages/SettingsProvider/res/values-da/strings.xml
+++ b/packages/SettingsProvider/res/values-da/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Lagring af indstillinger"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Ændringer af dine indstillinger for hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Dit hotspotbånd er ændret."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Denne enhed understøtter ikke din præference om kun 5 GHz. Denne enhed vil i stedet bruge 5 GHz-båndet, når det er muligt."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml
index ddcabaa..6e253e0 100644
--- a/packages/SettingsProvider/res/values-de/strings.xml
+++ b/packages/SettingsProvider/res/values-de/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Einstellungsspeicher"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Änderungen an deinen Hotspot-Einstellungen"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Dein Hotspot-Band hat sich geändert."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Dieses Gerät unterstützt die ausschließliche Nutzung von 5 GHz nicht. Es greift aber immer auf das 5-GHz-Band zurück, wenn dieses verfügbar ist."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-el/strings.xml b/packages/SettingsProvider/res/values-el/strings.xml
index 924fab5..c47fea2 100644
--- a/packages/SettingsProvider/res/values-el/strings.xml
+++ b/packages/SettingsProvider/res/values-el/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Αποθηκευτικός χώρος ρυθμίσεων"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Αλλαγές στις ρυθμίσεις σημείου πρόσβασης Wi-Fi"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Το εύρος σημείου πρόσβασης Wi-Fi άλλαξε."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Αυτή η συσκευή δεν υποστηρίζει την προτίμησή σας για αποκλειστική χρήση του εύρους 5 GHz. Αντ\' αυτού, αυτή η συσκευή θα χρησιμοποιεί το εύρος 5 GHz όταν είναι διαθέσιμο."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-en-rAU/strings.xml b/packages/SettingsProvider/res/values-en-rAU/strings.xml
index 05cd54e..fac51d83 100644
--- a/packages/SettingsProvider/res/values-en-rAU/strings.xml
+++ b/packages/SettingsProvider/res/values-en-rAU/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Changes to your hotspot settings"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Your hotspot band has changed."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-en-rCA/strings.xml b/packages/SettingsProvider/res/values-en-rCA/strings.xml
index 05cd54e..fac51d83 100644
--- a/packages/SettingsProvider/res/values-en-rCA/strings.xml
+++ b/packages/SettingsProvider/res/values-en-rCA/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Changes to your hotspot settings"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Your hotspot band has changed."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-en-rGB/strings.xml b/packages/SettingsProvider/res/values-en-rGB/strings.xml
index 05cd54e..fac51d83 100644
--- a/packages/SettingsProvider/res/values-en-rGB/strings.xml
+++ b/packages/SettingsProvider/res/values-en-rGB/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Changes to your hotspot settings"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Your hotspot band has changed."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-en-rIN/strings.xml b/packages/SettingsProvider/res/values-en-rIN/strings.xml
index 05cd54e..fac51d83 100644
--- a/packages/SettingsProvider/res/values-en-rIN/strings.xml
+++ b/packages/SettingsProvider/res/values-en-rIN/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Changes to your hotspot settings"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Your hotspot band has changed."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-es-rUS/strings.xml b/packages/SettingsProvider/res/values-es-rUS/strings.xml
index d5e6da9..af90257 100644
--- a/packages/SettingsProvider/res/values-es-rUS/strings.xml
+++ b/packages/SettingsProvider/res/values-es-rUS/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Cambios en la configuración de tu hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Cambió la banda de tu hotspot."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Si bien este dispositivo no admite la opción para conectarse exclusivamente a bandas de 5 GHz, las usará cuando estén disponibles."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml
index d5e6da9..ff4ee38 100644
--- a/packages/SettingsProvider/res/values-es/strings.xml
+++ b/packages/SettingsProvider/res/values-es/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Cambios en los ajustes del punto de acceso"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"La banda de tu punto de acceso ha cambiado."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Este dispositivo no admite la opción de conectarse únicamente a bandas de 5 GHz, pero las usará cuando estén disponibles."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-et/strings.xml b/packages/SettingsProvider/res/values-et/strings.xml
index a3e4db6..a0ec593 100644
--- a/packages/SettingsProvider/res/values-et/strings.xml
+++ b/packages/SettingsProvider/res/values-et/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Seadete talletusruum"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Muudatused teie kuumkoha seadetes"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Teie kuumkoha sagedusriba on muutunud."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"See seade ei toeta teie eelistatud ainult 5 GHz riba. Seade kasutab 5 GHz riba ainult siis, kui see on saadaval."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-eu/strings.xml b/packages/SettingsProvider/res/values-eu/strings.xml
index 8d410de1..220b486 100644
--- a/packages/SettingsProvider/res/values-eu/strings.xml
+++ b/packages/SettingsProvider/res/values-eu/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Ezarpenen biltegia"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Aldaketak egin dira sare publikoaren ezarpenetan"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Aldatu da sare publikoaren banda."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Gailuak ez du onartzen 5 GHz-ko banda soilik erabiltzeko hobespena. Horren ordez, erabilgarri dagoen bakoitzean erabiliko da 5 GHz-ko banda."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-fa/strings.xml b/packages/SettingsProvider/res/values-fa/strings.xml
index ed9d168..6819d2f 100644
--- a/packages/SettingsProvider/res/values-fa/strings.xml
+++ b/packages/SettingsProvider/res/values-fa/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"تنظیم محل ذخیره"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"تغییرات در تنظیمات نقطه اتصال"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"نوار نقطه اتصال شما تغییر کرد."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"این دستگاه از اولویت فقط ۵ گیگاهرتز شما پشتیبانی نمی‌کند. هرزمان نوار ۵ گیگاهرتزی دردسترس باشد، این دستگاه از آن استفاده خواهد کرد."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-fi/strings.xml b/packages/SettingsProvider/res/values-fi/strings.xml
index 9ff2c41..9ad01eb 100644
--- a/packages/SettingsProvider/res/values-fi/strings.xml
+++ b/packages/SettingsProvider/res/values-fi/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Asetuksien tallennus"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Hotspot-asetustesi muutokset"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Hotspot-taajuutesi on muuttunut."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Tämä laite ei tue asetustasi (vain 5 GHz). Sen sijaan laite käyttää 5 GHz:n taajuutta sen ollessa käytettävissä."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-fr-rCA/strings.xml b/packages/SettingsProvider/res/values-fr-rCA/strings.xml
index fdfdb1d..62951bd 100644
--- a/packages/SettingsProvider/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsProvider/res/values-fr-rCA/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Modifications apportées à vos paramètres de point d\'accès"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"La bande de votre point d\'accès a changé."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Cet appareil ne prend pas en charge votre préférence pour la bande de 5 GHz seulement. Au lieu de cela, cet appareil utilisera la bande de 5 GHz lorsqu\'elle sera disponible."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-fr/strings.xml b/packages/SettingsProvider/res/values-fr/strings.xml
index fdfdb1d..56bc65b 100644
--- a/packages/SettingsProvider/res/values-fr/strings.xml
+++ b/packages/SettingsProvider/res/values-fr/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Modifications apportées à vos paramètres de point d\'accès"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"La bande utilisée par votre point d\'accès a été modifiée."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Cet appareil n\'est pas conçu pour utiliser exclusivement la bande 5 GHz, mais il l\'utilisera chaque fois que disponible."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-gl/strings.xml b/packages/SettingsProvider/res/values-gl/strings.xml
index 7b1599e..771fade 100644
--- a/packages/SettingsProvider/res/values-gl/strings.xml
+++ b/packages/SettingsProvider/res/values-gl/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Almacenamento da configuración"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Cambios na configuración da zona wifi"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Modificouse a banda da zona wifi."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Este dispositivo non admite a opción de conectarse só a bandas de 5 GHz, pero usaraas se están dispoñibles."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-gu/strings.xml b/packages/SettingsProvider/res/values-gu/strings.xml
index 00246f9..a561924 100644
--- a/packages/SettingsProvider/res/values-gu/strings.xml
+++ b/packages/SettingsProvider/res/values-gu/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"સેટિંગ્સ સંગ્રહ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"તમારા હૉટસ્પૉટ સેટિંગને બદલે છે"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"તમારું હૉટસ્પૉટ બૅન્ડ બદલાઈ ગયું છે."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"આ ડિવાઇસ તમારી ફક્ત 5GHz માટેની પસંદગીને સપોર્ટ કરતું નથી. તેના બદલે, જ્યારે 5GHz બૅન્ડ ઉપલબ્ધ હશે ત્યારે આ ડિવાઇસ તેનો ઉપયોગ કરશે."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-hi/strings.xml b/packages/SettingsProvider/res/values-hi/strings.xml
index 35ed78f..199a546 100644
--- a/packages/SettingsProvider/res/values-hi/strings.xml
+++ b/packages/SettingsProvider/res/values-hi/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"सेटिंग मेमोरी"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"आपकी हॉटस्पॉट की सेटिंग में किए गए बदलाव"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"आपका हॉटस्पॉट का बैंड बदल दिया गया है."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"इस डिवाइस पर आप \'सिर्फ़ 5 गीगाहर्ट्ज़\' वाला विकल्प नहीं चुन सकते. इसके बजाय, 5 गीगाहर्ट्ज़ बैंड उपलब्ध होने पर यह डिवाइस उसका इस्तेमाल करेगा."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-hr/strings.xml b/packages/SettingsProvider/res/values-hr/strings.xml
index 070d061..9129a04 100644
--- a/packages/SettingsProvider/res/values-hr/strings.xml
+++ b/packages/SettingsProvider/res/values-hr/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Postavke pohrane"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Promjene postavki vaše žarišne točke"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Promijenila se frekvencija vaše žarišne točke."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Ovaj uređaj ne podržava vašu postavku za upotrebu samo 5 GHz. Upotrebljavat će frekvenciju od 5 GHz kada je dostupna."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-hu/strings.xml b/packages/SettingsProvider/res/values-hu/strings.xml
index 97124ae..a1ed494 100644
--- a/packages/SettingsProvider/res/values-hu/strings.xml
+++ b/packages/SettingsProvider/res/values-hu/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Beállítástároló"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"A hotspot beállításainak módosítása"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"A hotspot sávja megváltozott."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Ez az eszköz nem támogatja a csak 5 GHz-es sávra vonatkozó beállítást. Az eszköz akkor használ 5 GHz-es sávot, ha a sáv rendelkezésre áll."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-hy/strings.xml b/packages/SettingsProvider/res/values-hy/strings.xml
index d494012..6d716f8 100644
--- a/packages/SettingsProvider/res/values-hy/strings.xml
+++ b/packages/SettingsProvider/res/values-hy/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Կարգավորումների պահուստ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Փոփոխություններ թեժ կետի կարգավորումներում"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Ձեր թեժ կետի հաճախականությունը փոխվել է։"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Սարքը չի կարող աշխատել միայն 5 ԳՀց հաճախականությամբ։ Այդ հաճախականությունը կօգտագործվի հնարավորության դեպքում։"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-in/strings.xml b/packages/SettingsProvider/res/values-in/strings.xml
index 4ec8f84..8b1b1f4 100644
--- a/packages/SettingsProvider/res/values-in/strings.xml
+++ b/packages/SettingsProvider/res/values-in/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Setelan Penyimpanan"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Perubahan pada setelan hotspot Anda"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Band hotspot Anda telah berubah."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Perangkat ini tidak mendukung preferensi Anda, yaitu hanya 5GHz. Sebagai gantinya, perangkat ini akan menggunakan band 5GHz jika tersedia."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-is/strings.xml b/packages/SettingsProvider/res/values-is/strings.xml
index d75abae..150c084 100644
--- a/packages/SettingsProvider/res/values-is/strings.xml
+++ b/packages/SettingsProvider/res/values-is/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Stillingageymsla"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Breytingar á stillingum heits reits"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Tíðnisvið heita reitsins hefur breyst."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Þetta tæki styður ekki val þitt fyrir aðeins 5 GHz. Í staðinn mun þetta tæki nota 5 GHz tíðnisvið þegar það er í boði."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-it/strings.xml b/packages/SettingsProvider/res/values-it/strings.xml
index a1e3901..6715c3c 100644
--- a/packages/SettingsProvider/res/values-it/strings.xml
+++ b/packages/SettingsProvider/res/values-it/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Memoria impostazioni"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Modifiche alle tue impostazioni dell\'hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"La banda dell\'hotspot è cambiata."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Questo dispositivo non supporta la tua preferenza esclusiva per 5 GHz. Utilizzerà la banda a 5 GHz solo quando è disponibile."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-iw/strings.xml b/packages/SettingsProvider/res/values-iw/strings.xml
index c14f776..dd44329 100644
--- a/packages/SettingsProvider/res/values-iw/strings.xml
+++ b/packages/SettingsProvider/res/values-iw/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"אחסון הגדרות"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"שינויים להגדרות של הנקודה לשיתוף אינטרנט"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"התדר של הנקודה לשיתוף אינטרנט השתנה."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"‏מכשיר זה לא תומך בהעדפות שלך ל-5GHz בלבד. במקום זאת, מכשיר זה ישתמש בתדר 5GHz כשיהיה זמין."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ja/strings.xml b/packages/SettingsProvider/res/values-ja/strings.xml
index b11ec3b..7bbcd46 100644
--- a/packages/SettingsProvider/res/values-ja/strings.xml
+++ b/packages/SettingsProvider/res/values-ja/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ストレージの設定"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"アクセス ポイントの設定の変更"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"アクセス ポイントの帯域幅が変更されました。"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"このデバイスは 5 GHz のみという設定に対応していません。ただし、5 GHz 周波数帯が利用できるときには利用します。"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ka/strings.xml b/packages/SettingsProvider/res/values-ka/strings.xml
index d08e71e..86db4f3 100644
--- a/packages/SettingsProvider/res/values-ka/strings.xml
+++ b/packages/SettingsProvider/res/values-ka/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"პარამეტრების საცავი"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"თქვენი უსადენო ქსელის პარამეტრების ცვლილება"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"თქვენი უსადენო ქსელის დიაპაზონი შეიცვალა."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ამ მოწყობილობას არ შეუძლია მხოლოდ 5 გჰც სიხშირეზე მუშაობა. აღნიშნული სიხშირის გამოყენება მოხდება მაშინ, როცა ეს შესაძლებელია."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-kk/strings.xml b/packages/SettingsProvider/res/values-kk/strings.xml
index c07264c..a093d08 100644
--- a/packages/SettingsProvider/res/values-kk/strings.xml
+++ b/packages/SettingsProvider/res/values-kk/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Параметрлер жады"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Хотспот параметрлеріне өзгерістер енгізілді"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Хотспот жолағы өзгертілді."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Бұл құрылғы тек 5 ГГц жиілікте жұмыс істей алмайды. Бұл жиілік мүмкін болған жағдайда ғана қолданылады."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-km/strings.xml b/packages/SettingsProvider/res/values-km/strings.xml
index c880ead..f0a2712 100644
--- a/packages/SettingsProvider/res/values-km/strings.xml
+++ b/packages/SettingsProvider/res/values-km/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"កំណត់​ការ​ផ្ទុក"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ប្ដូរ​ទៅ​ការ​កំណត់​ហតស្ប៉ត​របស់អ្នក"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"កម្រិតបញ្ជូន​ហតស្ប៉ត​របស់​អ្នកបាន​ផ្លាស់ប្ដូរ។"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ឧបករណ៍នេះ​មិនស្គាល់​ចំណូលចិត្ត​របស់អ្នក​សម្រាប់តែ 5GHz ប៉ុណ្ណោះ។ ផ្ទុយមកវិញ ឧបករណ៍នេះ​នឹងប្រើ​កម្រិតបញ្ជូន 5GHz នៅពេល​ដែលអាច​ប្រើបាន។"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-kn/strings.xml b/packages/SettingsProvider/res/values-kn/strings.xml
index d823323..f2c1d5e 100644
--- a/packages/SettingsProvider/res/values-kn/strings.xml
+++ b/packages/SettingsProvider/res/values-kn/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಸಂಗ್ರಹಣೆ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ನಿಮ್ಮ ಹಾಟ್‌ಸ್ಪಾಟ್‌ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿನ ಬದಲಾವಣೆಗಳು"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ನಿಮ್ಮ ಹಾಟ್‌ಸ್ಪಾಟ್‌ ಬ್ಯಾಂಡ್ ಬದಲಾಗಿದೆ."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ಈ ಸಾಧನವು 5GHz ಗೆ ಮಾತ್ರ ನಿಮ್ಮ ಆದ್ಯತೆಯನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ. ಬದಲಿಗೆ, ಈ ಸಾಧನವು 5GHz ಬ್ಯಾಂಡ್ ಅನ್ನು ಲಭ್ಯವಿರುವಾಗ ಬಳಸುತ್ತದೆ."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ko/strings.xml b/packages/SettingsProvider/res/values-ko/strings.xml
index ab8fb2b..841832d 100644
--- a/packages/SettingsProvider/res/values-ko/strings.xml
+++ b/packages/SettingsProvider/res/values-ko/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"설정 저장소"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"핫스팟 설정 변경"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"핫스팟 대역이 변경되었습니다."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"이 기기에서는 5GHz 전용 환경설정이 지원되지 않습니다. 대신 가능할 때만 기기에서 5GHz 대역이 사용됩니다."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ky/strings.xml b/packages/SettingsProvider/res/values-ky/strings.xml
index 566c481..014c66c 100644
--- a/packages/SettingsProvider/res/values-ky/strings.xml
+++ b/packages/SettingsProvider/res/values-ky/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Жөндөөлөрдү сактоо"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Байланыш түйүнүңүздүн жөндөөлөрү өзгөрүлдү"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Байланыш түйүнүңүздүн жыштыгы өзгөрдү."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Бул түзмөк 5ГГцти гана колдонуу жөндөөсүн колдоого албайт. Анын ордуна, бул түзмөк 5ГГц жыштыгын ал жеткиликтүү болгондо колдонот."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-lo/strings.xml b/packages/SettingsProvider/res/values-lo/strings.xml
index 1aa5fe9..9d60ba1 100644
--- a/packages/SettingsProvider/res/values-lo/strings.xml
+++ b/packages/SettingsProvider/res/values-lo/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ບ່ອນເກັບຂໍ້ມູນການຕັ້ງຄ່າ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ການປ່ຽນແປງການຕັ້ງຄ່າຮັອດສະປອດຂອງທ່ານ"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ຄື້ນຄວາມຖີ່ຮັອດສະປອດຂອງທ່ານປ່ຽນແປງແລ້ວ."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ອຸປະກອນນີ້ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂອງທ່ານສຳລັບ 5GHz ເທົ່ານັ້ນ. ແຕ່ວ່າອຸປະກອນນີ້ຈະໃຊ້ຄື້ນຄວາມຖີ່ 5GHz ເມື່ອສາມາດໃຊ້ໄດ້."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-lt/strings.xml b/packages/SettingsProvider/res/values-lt/strings.xml
index 47cd6b4..775d3b9 100644
--- a/packages/SettingsProvider/res/values-lt/strings.xml
+++ b/packages/SettingsProvider/res/values-lt/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Nustatymų saugykla"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Viešosios interneto prieigos taško nustatymų pakeitimai"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Viešosios prieigos taško dažnio juosta pasikeitė."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Šiame įrenginyje nepalaikoma tik 5 GHz nuostata. Vietoj to šiame įrenginyje bus naudojama 5 GHz dažnio juosta, kai bus pasiekiama."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-lv/strings.xml b/packages/SettingsProvider/res/values-lv/strings.xml
index d221d46..f7f3117 100644
--- a/packages/SettingsProvider/res/values-lv/strings.xml
+++ b/packages/SettingsProvider/res/values-lv/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Iestatījumu krātuve"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Izmaiņas tīklāja iestatījumos"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Ir mainīts tīklāja joslas platums."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Šajā ierīcē netiek atbalstīta jūsu preference par tikai 5 GHz joslu. 5 GHz josla ierīcē tiks izmantota, kad tā būs pieejama."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-mk/strings.xml b/packages/SettingsProvider/res/values-mk/strings.xml
index dc74c4a..a245e5f 100644
--- a/packages/SettingsProvider/res/values-mk/strings.xml
+++ b/packages/SettingsProvider/res/values-mk/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Поставки за меморија"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Промени на поставките за точка на пристап"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Опсегот за точка на пристап е променет."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Уредов не ги поддржува вашите поставки за само 5 GHz. Наместо тоа, ќе го користи опсегот од 5 GHz кога е достапен."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ml/strings.xml b/packages/SettingsProvider/res/values-ml/strings.xml
index a11e236..b63f20e 100644
--- a/packages/SettingsProvider/res/values-ml/strings.xml
+++ b/packages/SettingsProvider/res/values-ml/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"സംഭരണ ക്രമീകരണം"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ക്രമീകരണത്തിൽ വരുത്തിയ മാറ്റങ്ങൾ"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ബാൻഡ് മാറിയിരിക്കുന്നു."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"നിങ്ങളുടെ മുൻഗണനയനുസരിച്ചുള്ള, 5GHz മാത്രം എന്നത് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല. പകരം, 5GHz ബാൻഡ് ലഭ്യമാകുമ്പോൾ അത് ഉപയോഗിക്കും."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-mn/strings.xml b/packages/SettingsProvider/res/values-mn/strings.xml
index f6437c75..c839177 100644
--- a/packages/SettingsProvider/res/values-mn/strings.xml
+++ b/packages/SettingsProvider/res/values-mn/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Тохиргооны Сан"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Таны сүлжээний цэгийн тохиргооны өөрчлөлт"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Таны сүлжээний цэгийн хязгаарыг өөрчилсөн."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Энэ төхөөрөмж нь зөвхөн 5Гц гэсэн таны сонголтыг дэмждэггүй. Оронд нь энэ төхөөрөмж 5Гц-н хязгаарыг боломжтой үед нь ашиглах болно."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-mr/strings.xml b/packages/SettingsProvider/res/values-mr/strings.xml
index 7888488..0c7041e 100644
--- a/packages/SettingsProvider/res/values-mr/strings.xml
+++ b/packages/SettingsProvider/res/values-mr/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"सेटिंग्ज संचयन"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"तुमच्या हॉटस्पॉट सेटिंग्जमधील बदल"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"तुमचा हॉटस्पॉट बँड बदलला गेला आहे."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"हे डिव्हाइस फक्त ५GHz च्या तुमच्या प्राधान्याला सपोर्ट करत नाही. त्याऐवजी, उपलब्ध असेल तेव्हा हे डिव्हाइस ५GHz बँड वापरेल."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ms/strings.xml b/packages/SettingsProvider/res/values-ms/strings.xml
index bcde71c..a1574df 100644
--- a/packages/SettingsProvider/res/values-ms/strings.xml
+++ b/packages/SettingsProvider/res/values-ms/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Storan Tetapan"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Perubahan kepada tetapan tempat liputan anda"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Jalur tempat liputan anda telah berubah."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Peranti ini tidak menyokong pilihan anda untuk 5GHz sahaja. Sebaliknya, peranti ini akan menggunakan jalur 5GHz apabila tersedia."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-my/strings.xml b/packages/SettingsProvider/res/values-my/strings.xml
index b2e670e..48d4dba 100644
--- a/packages/SettingsProvider/res/values-my/strings.xml
+++ b/packages/SettingsProvider/res/values-my/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"သိုလှောင်မှုဆက်တင်များ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"သင်၏ဟော့စပေါ့ ဆက်တင်များ ပြောင်းလဲမှု"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"သင်၏ ဟော့စပေါ့လိုင်း ပြောင်းသွားပါပြီ။"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ဤစက်ပစ္စည်းသည် သင်၏ 5GHz သီးသန့်ရွေးချယ်မှုအတွက် ပံ့ပိုးမထားပါ။ ၎င်းအစား ဤစက်ပစ္စည်းသည် ရနိုင်သည့်အခါ 5GHz လိုင်းကို သုံးသွားပါမည်။"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-nb/strings.xml b/packages/SettingsProvider/res/values-nb/strings.xml
index 5c60ad7..e0cbd7e 100644
--- a/packages/SettingsProvider/res/values-nb/strings.xml
+++ b/packages/SettingsProvider/res/values-nb/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Lagring av innstillinger"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Endres til innstillingene dine for Wi-Fi-soner"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Båndet ditt for Wi-Fi-sone er endret."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Denne enheten støtter ikke innstillingen din for bare 5 GHz. I stedet bruker enheten 5 GHz-båndet når det er tilgjengelig."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ne/strings.xml b/packages/SettingsProvider/res/values-ne/strings.xml
index 8c4f8c8..2fd9b00 100644
--- a/packages/SettingsProvider/res/values-ne/strings.xml
+++ b/packages/SettingsProvider/res/values-ne/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"सेटिङहरू भण्डारण"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"तपाईंका हटस्पट सेटिङहरूमा गरिएका परिवर्तनहरू"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"तपाईंको हटस्पट ब्यान्ड परिवर्तन भएको छ।"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"यो यन्त्रले तपाईंको 5GHz मात्रको प्राथमिकतालाई समर्थन गर्दैन। बरु, उपलब्ध भएको खण्डमा यो यन्त्रले 5GHz ब्यान्ड प्रयोग गर्ने छ।"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-nl/strings.xml b/packages/SettingsProvider/res/values-nl/strings.xml
index 7ad4588..0b843ae 100644
--- a/packages/SettingsProvider/res/values-nl/strings.xml
+++ b/packages/SettingsProvider/res/values-nl/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Opslagruimte voor instellingen"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Wijzigingen in je hotspot-instellingen"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Je hotspot-band is gewijzigd."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Dit apparaat biedt geen ondersteuning voor je voorkeur voor alleen 5 GHz. In plaats daarvan gebruikt dit apparaat de 5-GHz-band wanneer deze beschikbaar is."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 1837219..53f6104 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍‌"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ଆପଣଙ୍କର ହଟ୍‌ସ୍ପଟ୍ ସେଟିଂସ୍‌କୁ ବଦଳାଇଥାଏ"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ଆପଣଙ୍କର ହଟ୍‌ସ୍ପଟ୍ ପରିବର୍ତ୍ତନ କରାଯାଇଛି।"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"କେବଳ 5GHz ପାଇଁ, ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କର ପସନ୍ଦକୁ ସମର୍ଥନ କରେ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ, ଉପଲବ୍ଧ ହେଲେ ଏହି ଡିଭାଇସ୍ 5GHz ବ୍ୟାଣ୍ଡ ବ୍ୟବହାର କରିବ।"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pa/strings.xml b/packages/SettingsProvider/res/values-pa/strings.xml
index 2961435..9a41e36 100644
--- a/packages/SettingsProvider/res/values-pa/strings.xml
+++ b/packages/SettingsProvider/res/values-pa/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ਸੈਟਿੰਗਾਂ ਸਟੋਰੇਜ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ਤੁਹਾਡੀਆਂ ਹੌਟਸਪੌਟ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲਾਅ"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ਤੁਹਾਡਾ ਹੌਟਸਪੌਟ ਬੈਂਡ ਬਦਲ ਗਿਆ ਹੈ।"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ਇਹ ਡੀਵਾਈਸ ਸਿਰਫ਼ 5GHz ਦੀ ਤੁਹਾਡੀ ਤਰਜੀਹ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ ਹੈ। ਇਸਦੀ ਬਜਾਏ, ਇਹ ਡੀਵਾਈਸ ਉਪਲਬਧ ਹੋਣ \'ਤੇ 5GHz ਬੈਂਡ ਵਰਤੇਗਾ।"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pl/strings.xml b/packages/SettingsProvider/res/values-pl/strings.xml
index 9963aee..7fd2b13 100644
--- a/packages/SettingsProvider/res/values-pl/strings.xml
+++ b/packages/SettingsProvider/res/values-pl/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Pamięć ustawień"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Zmieniono ustawienia hotspotu"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Zmieniono pasmo hotspotu."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"To urządzenie nie może korzystać tylko z częstotliwości 5 GHz. Będzie korzystać z tego pasma, jeśli będzie ono dostępne."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pt-rBR/strings.xml b/packages/SettingsProvider/res/values-pt-rBR/strings.xml
index e25e82e..18db8f6 100644
--- a/packages/SettingsProvider/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsProvider/res/values-pt-rBR/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Armazenamento de configurações"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Mudanças nas suas configurações de ponto de acesso"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Sua banda de ponto de acesso foi modificada."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pt-rPT/strings.xml b/packages/SettingsProvider/res/values-pt-rPT/strings.xml
index 3b95a31..be88cce 100644
--- a/packages/SettingsProvider/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsProvider/res/values-pt-rPT/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Armazenamento de definições"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Alterações às definições de zona Wi-Fi"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"A banda da sua zona Wi-Fi foi alterada."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Este dispositivo não suporta a sua preferência apenas para 5 GHz. Em alternativa, este dispositivo vai utilizar a banda de 5 GHz quando estiver disponível."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-pt/strings.xml b/packages/SettingsProvider/res/values-pt/strings.xml
index e25e82e..18db8f6 100644
--- a/packages/SettingsProvider/res/values-pt/strings.xml
+++ b/packages/SettingsProvider/res/values-pt/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Armazenamento de configurações"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Mudanças nas suas configurações de ponto de acesso"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Sua banda de ponto de acesso foi modificada."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ro/strings.xml b/packages/SettingsProvider/res/values-ro/strings.xml
index 5a5ac6d..3a234e1 100644
--- a/packages/SettingsProvider/res/values-ro/strings.xml
+++ b/packages/SettingsProvider/res/values-ro/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Stocare setări"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Modificări aduse setărilor pentru hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"S-a schimbat banda de frecvență a hotspotului."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Dispozitivul nu acceptă doar preferința pentru 5 GHz. Dispozitivul va folosi banda de 5 GHz când este disponibilă."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ru/strings.xml b/packages/SettingsProvider/res/values-ru/strings.xml
index 15ca313..184afdd 100644
--- a/packages/SettingsProvider/res/values-ru/strings.xml
+++ b/packages/SettingsProvider/res/values-ru/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Хранилище настроек"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Изменения в настройках точки доступа"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Частота точки доступа изменена."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Устройство не может работать только на частоте 5 ГГц. Эта частота будет использоваться, когда это возможно."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-si/strings.xml b/packages/SettingsProvider/res/values-si/strings.xml
index feff43c..69e04f1 100644
--- a/packages/SettingsProvider/res/values-si/strings.xml
+++ b/packages/SettingsProvider/res/values-si/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"සැකසීම් ගබඩාව"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"ඔබගේ හොට්ස්පොට් සැකසීම්වලට වෙනස් කිරීම්"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ඔබගේ හොට්ස්පොට් කලාපය වෙනස් වී ඇත."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"මෙම උපාංගය 5GHz සඳහා ඔබේ මනාපවලට සහාය නොදක්වයි. ඒ වෙනුවට, මෙම උපාංගය ලබා ගත හැකි විට 5GHz කලාපය භාවිතා කරනු ඇත."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sk/strings.xml b/packages/SettingsProvider/res/values-sk/strings.xml
index 1207a94..a53178d 100644
--- a/packages/SettingsProvider/res/values-sk/strings.xml
+++ b/packages/SettingsProvider/res/values-sk/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Ukladací priestor nastavení"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Zmeny nastavení hotspotu"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Pásmo vášho hotspotu sa zmenilo."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Toto zariadenie nepodporuje vašu predvoľbu používať iba 5 GHz. Namiesto toho bude pásmo 5 GHz používať vtedy, keď bude k dispozícii."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sl/strings.xml b/packages/SettingsProvider/res/values-sl/strings.xml
index 28a9937..ea697fe 100644
--- a/packages/SettingsProvider/res/values-sl/strings.xml
+++ b/packages/SettingsProvider/res/values-sl/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Shramba nastavitev"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Spremembe nastavitev dostopne točke"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Pas dostopne točke je spremenjen."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Ta naprava ne podpira prednostne nastavitve samo za 5-GHz pas. Namesto tega bo ta naprava uporabljala 5-GHz pas, ko bo na voljo."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sq/strings.xml b/packages/SettingsProvider/res/values-sq/strings.xml
index 977fe02..a111576 100644
--- a/packages/SettingsProvider/res/values-sq/strings.xml
+++ b/packages/SettingsProvider/res/values-sq/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Hapësira ruajtëse e \"Cilësimeve\""</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Ndryshimet në cilësimet e zonës së qasjes për internet"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Brezi yt i zonës së qasjes për internet ka ndryshuar."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Kjo pajisje nuk e mbështet preferencën për vetëm 5 GHz. Përkundrazi, pajisja do të përdorë brezin 5 GHz nëse ka."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sr/strings.xml b/packages/SettingsProvider/res/values-sr/strings.xml
index 74b9dde..d473102 100644
--- a/packages/SettingsProvider/res/values-sr/strings.xml
+++ b/packages/SettingsProvider/res/values-sr/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Подешавања складишта"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Промене подешавања за хотспот"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Опсег хотспота је промењен."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Овај уређај не подржава подешавање само за 5 GHz. Уређај ће користити опсег од 5 GHz када буде доступан."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sv/strings.xml b/packages/SettingsProvider/res/values-sv/strings.xml
index 1444626..fea3e5e 100644
--- a/packages/SettingsProvider/res/values-sv/strings.xml
+++ b/packages/SettingsProvider/res/values-sv/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Lagring av inställningar"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Ändringar i inställningarna för surfzon"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Frekvensbandet för surfzonen har ändrats."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Den här enheten har inte stöd för inställningen för att endast använda 5 GHz. I stället används 5 GHz när det är möjligt."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-sw/strings.xml b/packages/SettingsProvider/res/values-sw/strings.xml
index c244d88..4d05817 100644
--- a/packages/SettingsProvider/res/values-sw/strings.xml
+++ b/packages/SettingsProvider/res/values-sw/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Hifadhi ya Mipangilio"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Mabadiliko kwenye mipangilio ya mtandaopepe"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Bendi ya mtandaopepe wako imebadilika."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Kifaa hiki hakitumii mapendeleo yako ya GHz 5 pekee. Badala yake, kifaa hiki kitatumia bendi ya GHz 5 itakapopatikana."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ta/strings.xml b/packages/SettingsProvider/res/values-ta/strings.xml
index b26c875..f518a78 100644
--- a/packages/SettingsProvider/res/values-ta/strings.xml
+++ b/packages/SettingsProvider/res/values-ta/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"அமைப்புகளின் சேமிப்பிடம்"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"உங்கள் ஹாட்ஸ்பாட் அமைப்புகளில் செய்யப்பட்டுள்ள மாற்றங்கள்"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"உங்கள் ஹாட்ஸ்பாட்டின் அலைவரிசை வரம்பு மாறிவிட்டது."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"இந்தச் சாதனத்தில், ’5GHz மட்டும்’ எனும் முன்னுரிமைத் தேர்வு ஆதரிக்கப்படவில்லை. எனினும் 5GHz அலைவரிசை வரம்பிற்குள் இருக்கும்போது சாதனம் அதைப் பயன்படுத்திக்கொள்ளும்."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-te/strings.xml b/packages/SettingsProvider/res/values-te/strings.xml
index 2a4971a..6c59223 100644
--- a/packages/SettingsProvider/res/values-te/strings.xml
+++ b/packages/SettingsProvider/res/values-te/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"సెట్టింగ్‌ల నిల్వ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"మీ హాట్‌స్పాట్ సెట్టింగ్‌లకు మార్పులు"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"మీ హాట్‌స్పాట్ బ్యాండ్ మార్చబడింది."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"ఈ పరికరం 5GHz కోసం మాత్రమే మీ ప్రాధాన్యతకు మద్దతు ఇవ్వదు. బదులుగా, ఈ పరికరం అందుబాటులో ఉన్నప్పుడు 5GHz బ్యాండ్‌ను ఉపయోగిస్తుంది."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-th/strings.xml b/packages/SettingsProvider/res/values-th/strings.xml
index db47654..4bf148f 100644
--- a/packages/SettingsProvider/res/values-th/strings.xml
+++ b/packages/SettingsProvider/res/values-th/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ที่เก็บข้อมูลการตั้งค่า"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"มีการเปลี่ยนแปลงการตั้งค่าฮอตสปอต"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"ย่านความถี่ฮอตสปอตมีการเปลี่ยนแปลง"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"อุปกรณ์นี้ไม่รองรับค่ากำหนดของคุณเฉพาะสำหรับ 5 GHz เท่านั้น และจะใช้ย่านความถี่ 5 GHz แทน เมื่อใช้ได้"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-tl/strings.xml b/packages/SettingsProvider/res/values-tl/strings.xml
index 71c6266..2a36d58 100644
--- a/packages/SettingsProvider/res/values-tl/strings.xml
+++ b/packages/SettingsProvider/res/values-tl/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Storage ng Mga Setting"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Mga pagbabago sa mga setting ng iyong hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Nagbago ang band ng iyong hotspot."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Hindi sinusuportahan ng device na ito ang kagustuhan mong gumamit lang ng 5GHz. Sa halip, gagamitin ng device na ito ang 5GHz na band kapag available."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-tr/strings.xml b/packages/SettingsProvider/res/values-tr/strings.xml
index 4737a1e..add1fdb 100644
--- a/packages/SettingsProvider/res/values-tr/strings.xml
+++ b/packages/SettingsProvider/res/values-tr/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Ayarlar Deposu"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Hotspot ayarlarınız değişti"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Hotspot bandınız değişti."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Bu cihaz yalnızca 5 GHz bandının kullanılmasına yönelik tercihinizi desteklemiyor. Bunun yerine, bu cihaz 5 GHz bandını mevcut olduğunda kullanacak."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-uk/strings.xml b/packages/SettingsProvider/res/values-uk/strings.xml
index 2c77c6a61..cd678bc 100644
--- a/packages/SettingsProvider/res/values-uk/strings.xml
+++ b/packages/SettingsProvider/res/values-uk/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Сховище налаштувань"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Зміни в налаштуваннях точки доступу"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Діапазон частот точки доступу змінено."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"На цьому пристрої не підтримується налаштування \"Лише 5 ГГц\". Натомість буде використано діапазон частот 5 ГГц (якщо доступно)."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-ur/strings.xml b/packages/SettingsProvider/res/values-ur/strings.xml
index 31694e0..2241ce9 100644
--- a/packages/SettingsProvider/res/values-ur/strings.xml
+++ b/packages/SettingsProvider/res/values-ur/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"ترتیبات کا اسٹوریج"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"اپنے ہاٹ اسپاٹ کی ترتیبات میں تبدیلیاں"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"آپ کا ہاٹ اسپات بینڈ تبدیل ہو گیا ہے۔"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"‏یہ آلہ صرف 5GHz کے لیے آپ کی ترجیح کو سپورٹ نہیں کرے گا۔ بلکہ 5GHz بینڈ کے دستیاب ہونے پر اس کا استعمال کرے گا۔"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-uz/strings.xml b/packages/SettingsProvider/res/values-uz/strings.xml
index 86a980e..a266bf0 100644
--- a/packages/SettingsProvider/res/values-uz/strings.xml
+++ b/packages/SettingsProvider/res/values-uz/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Sozlamalar xotirasi"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Hotspot sozlamalari o‘zgartirildi"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Hotspot chastotasi oʻzgartirildi."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Qurilma faqat 5 GGs chastotada ishlay olmaydi. Bu chastotadan imkoniyatga qarab foydalaniladi."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-vi/strings.xml b/packages/SettingsProvider/res/values-vi/strings.xml
index 6476927..74f93b2 100644
--- a/packages/SettingsProvider/res/values-vi/strings.xml
+++ b/packages/SettingsProvider/res/values-vi/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Lưu trữ bộ nhớ"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Những thay đổi trong mục cài đặt điểm phát sóng của bạn"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Bằng tần của điểm phát sóng đã thay đổi."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Thiết bị này không hỗ trợ tùy chọn chỉ sử dụng băng tần 5 GHz. Thay vào đó, thiết bị này sẽ sử dụng băng tần 5 GHz khi có thể."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-zh-rCN/strings.xml b/packages/SettingsProvider/res/values-zh-rCN/strings.xml
index 1395912..95b15e0 100644
--- a/packages/SettingsProvider/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsProvider/res/values-zh-rCN/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"设置存储"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"您的热点设置已变更"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"您的热点频段已变更。"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"此设备不支持您的偏好设置(仅限 5GHz),而且会在 5GHz 频段可用时使用该频段。"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-zh-rHK/strings.xml b/packages/SettingsProvider/res/values-zh-rHK/strings.xml
index 2845264..41ebe27 100644
--- a/packages/SettingsProvider/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsProvider/res/values-zh-rHK/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"您的熱點設定變更"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"您的熱點頻段已變更。"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"此裝置不支援只限 5 GHz 的偏好設定,但會在 5 GHz 頻段可用時採用。"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-zh-rTW/strings.xml b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
index 2845264..d0a30f5 100644
--- a/packages/SettingsProvider/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsProvider/res/values-zh-rTW/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"無線基地台設定變更"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"你的無線基地台頻帶已變更。"</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"這部裝置不支援你的偏好設定 (僅限 5GHz),而是會在 5GHz 可用時使用該頻帶。"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values-zu/strings.xml b/packages/SettingsProvider/res/values-zu/strings.xml
index 8c1d9e0..0440b3b 100644
--- a/packages/SettingsProvider/res/values-zu/strings.xml
+++ b/packages/SettingsProvider/res/values-zu/strings.xml
@@ -20,10 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Izilungiselelo zesitoreji"</string>
-    <!-- no translation found for wifi_softap_config_change (5338670993556993667) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5338670993556993667">"Ushintsho kuzilungiselelo zakho ze-hotspot"</string>
+    <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Ibhendi yakho ye-hotspot ishintshile."</string>
+    <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"Le divayisi ayisekeli okuncamelayo kwe-5GHz kuphela. Kunalokho, le divayisi izosebenzisa ibhendi ye-5GHz uma itholakala."</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 21b3ba3..c9e1944b 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -224,7 +224,7 @@
     <bool name="def_charging_sounds_enabled">true</bool>
 
     <!-- Default for Settings.Secure.NOTIFICATION_BUBBLES -->
-    <bool name="def_notification_bubbles">false</bool>
+    <bool name="def_notification_bubbles">true</bool>
 
     <!-- Default for Settings.Secure.AWARE_ENABLED -->
     <bool name="def_aware_enabled">false</bool>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 1f68742..987e82e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -72,5 +72,6 @@
         Settings.Global.NOTIFICATION_BUBBLES,
         Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
         Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER,
+        Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3b929b9..76e7ab4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -155,6 +155,7 @@
         Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED,
         Settings.Secure.AWARE_LOCK_ENABLED,
         Settings.Secure.AWARE_TAP_PAUSE_GESTURE_COUNT,
-        Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT
+        Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT,
+        Settings.Secure.PEOPLE_STRIP,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 3d278db..72923a3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -151,5 +151,6 @@
         VALIDATORS.put(Global.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 090af98..ae07598 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -234,5 +234,6 @@
         VALIDATORS.put(Secure.AWARE_LOCK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DISPLAY_DENSITY_FORCED, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.TAP_GESTURE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.PEOPLE_STRIP, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2027345..375a650 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -951,8 +951,7 @@
                                                 (1 << AudioManager.STREAM_NOTIFICATION) |
                                                 (1 << AudioManager.STREAM_SYSTEM) |
                                                 (1 << AudioManager.STREAM_SYSTEM_ENFORCED);
-                if (!mContext.getResources().getBoolean(
-                        com.android.internal.R.bool.config_voice_capable)) {
+                if (!getTelephonyManager().isVoiceCapable()) {
                     ringerModeAffectedStreams |= (1 << AudioManager.STREAM_MUSIC);
                 }
                 db.execSQL("DELETE FROM system WHERE name='"
@@ -2548,7 +2547,7 @@
             StringBuilder val = new StringBuilder();
             List<Integer> defaultNetworks = TelephonyProperties.default_network();
             int phoneCount = 1;
-            TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+            TelephonyManager telephonyManager = getTelephonyManager();
             if (telephonyManager != null) {
                 phoneCount = telephonyManager.getSupportedModemCount();
             }
@@ -2663,4 +2662,8 @@
     private String getDefaultDeviceName() {
         return mContext.getResources().getString(R.string.def_device_name_simple, Build.MODEL);
     }
+
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 443288c..c19a340 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -28,7 +28,7 @@
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.Uri;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
@@ -875,32 +875,23 @@
     }
 
     private byte[] getSoftAPConfiguration() {
-        try {
-            return mWifiManager.getWifiApConfiguration().getBytesForBackup();
-        } catch (IOException ioe) {
-            Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
-            return new byte[0];
-        }
+        return mWifiManager.retrieveSoftApBackupData();
     }
 
     private void restoreSoftApConfiguration(byte[] data) {
-        try {
-            WifiConfiguration config = WifiConfiguration
-                    .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
-            if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
-            int originalApBand = config.apBand;
-            mWifiManager.setWifiApConfiguration(config);
+        SoftApConfiguration config = mWifiManager.restoreSoftApBackupData(data);
+        if (config != null) {
+            int originalApBand = config.getBand();
+            if (DEBUG) Log.d(TAG, "Successfully unMarshaled SoftApConfiguration ");
 
             // Depending on device hardware, we may need to notify the user of a setting change for
             // the apBand preference
             boolean dualMode = mWifiManager.isDualModeSupported();
-            int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
+            int storedApBand = mWifiManager.getSoftApConfiguration().getBand();
             if (dualMode && storedApBand != originalApBand) {
                 Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
                 WifiSoftApBandChangedNotifier.notifyUserOfApBandConversion(this);
             }
-        } catch (IOException | BackupUtils.BadVersionException e) {
-            Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
         }
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 0a2dd38..80077c8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -691,6 +691,9 @@
         dumpRepeatedSetting(s, p,
                 Settings.Global.ERROR_LOGCAT_PREFIX,
                 GlobalSettingsProto.ERROR_LOGCAT_LINES);
+        dumpRepeatedSetting(s, p,
+                Settings.Global.MAX_ERROR_BYTES_PREFIX,
+                GlobalSettingsProto.MAX_ERROR_BYTES);
 
         final long euiccToken = p.start(GlobalSettingsProto.EUICC);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 93a1407..4309c80 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3264,7 +3264,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 184;
+            private static final int SETTINGS_VERSION = 185;
 
             private final int mUserId;
 
@@ -4446,20 +4446,15 @@
                 }
 
                 if (currentVersion == 182) {
-                    // Remove secure bubble settings.
+                    // Remove secure bubble settings; it's in global now.
                     getSecureSettingsLocked(userId).deleteSettingLocked("notification_bubbles");
 
-                    // Add global bubble settings.
-                    getGlobalSettingsLocked().insertSettingLocked(Global.NOTIFICATION_BUBBLES,
-                            getContext().getResources().getBoolean(
-                                    R.bool.def_notification_bubbles) ? "1" : "0", null /* tag */,
-                            true /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME);
-
+                    // Removed. Updated NOTIFICATION_BUBBLES to be true by default, see 184.
                     currentVersion = 183;
                 }
 
                 if (currentVersion == 183) {
-                    // Version 184: Set default values for WIRELESS_CHARGING_STARTED_SOUND
+                    // Version 183: Set default values for WIRELESS_CHARGING_STARTED_SOUND
                     // and CHARGING_STARTED_SOUND
                     final SettingsState globalSettings = getGlobalSettingsLocked();
 
@@ -4500,6 +4495,18 @@
                     currentVersion = 184;
                 }
 
+                if (currentVersion == 184) {
+                    // Version 184: Reset the default for Global Settings: NOTIFICATION_BUBBLES
+                    // This is originally set in version 182, however, the default value changed
+                    // so this step is to ensure the value is updated to the correct default.
+                    getGlobalSettingsLocked().insertSettingLocked(Global.NOTIFICATION_BUBBLES,
+                            getContext().getResources().getBoolean(
+                                    R.bool.def_notification_bubbles) ? "1" : "0", null /* tag */,
+                            true /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME);
+
+                    currentVersion = 185;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c23a494..4a10e85 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -223,7 +223,6 @@
                     Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
                     Settings.Global.DEVELOPMENT_FORCE_RTL,
                     Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
-                    Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
                     Settings.Global.DEVICE_DEMO_MODE,
                     Settings.Global.DEVICE_IDLE_CONSTANTS,
                     Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
@@ -324,6 +323,7 @@
                     Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS,
                     Settings.Global.LTE_SERVICE_FORCED,
                     Settings.Global.LID_BEHAVIOR,
+                    Settings.Global.MAX_ERROR_BYTES_PREFIX,
                     Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
                     Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
                     Settings.Global.MDC_INITIAL_MAX_RETRY,
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 70f8e15..deaafca 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
@@ -28,6 +28,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.annotation.NonNull;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
@@ -161,6 +162,23 @@
     }
 
     /**
+     * Removes the outdated snapshot of home task.
+     */
+    public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
+        mBackgroundExecutor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
+                            homeActivity.getActivityToken());
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to invalidate home snapshot", e);
+                }
+            }
+        });
+    }
+
+    /**
      * @return the activity label, badging if necessary.
      */
     public String getBadgedActivityLabel(ActivityInfo info, int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index d66a53c..caf5ee0 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -163,8 +163,7 @@
     public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode,
             boolean showMissingSim) {
         mContext = context;
-        mIsEmergencyCallCapable = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+        mIsEmergencyCallCapable = getTelephonyManager().isVoiceCapable();
 
         mShowAirplaneMode = showAirplaneMode;
         mShowMissingSim = showMissingSim;
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 867014b6..5d084e7 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -28,6 +28,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.MotionEvent;
@@ -86,13 +87,16 @@
 
     public EmergencyButton(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mIsVoiceCapable = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+        mIsVoiceCapable = getTelephonyManager().isVoiceCapable();
         mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
         mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
     }
 
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 9380eb4..4e7956d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -290,6 +290,7 @@
                     View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                             | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                             | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+            getWindow().setFitWindowInsetsTypes(0 /* types */);
             getWindow().setNavigationBarContrastEnforced(false);
             getWindow().setNavigationBarColor(Color.TRANSPARENT);
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
index 812f215..0210e08 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockInfo.java
@@ -25,12 +25,12 @@
 final class ClockInfo {
 
     private final String mName;
-    private final String mTitle;
+    private final Supplier<String> mTitle;
     private final String mId;
     private final Supplier<Bitmap> mThumbnail;
     private final Supplier<Bitmap> mPreview;
 
-    private ClockInfo(String name, String title, String id,
+    private ClockInfo(String name, Supplier<String> title, String id,
             Supplier<Bitmap> thumbnail, Supplier<Bitmap> preview) {
         mName = name;
         mTitle = title;
@@ -50,7 +50,7 @@
      * Gets the name (title) of the clock face to be shown in the picker app.
      */
     String getTitle() {
-        return mTitle;
+        return mTitle.get();
     }
 
     /**
@@ -80,7 +80,7 @@
 
     static class Builder {
         private String mName;
-        private String mTitle;
+        private Supplier<String> mTitle;
         private String mId;
         private Supplier<Bitmap> mThumbnail;
         private Supplier<Bitmap> mPreview;
@@ -94,7 +94,7 @@
             return this;
         }
 
-        public Builder setTitle(String title) {
+        public Builder setTitle(Supplier<String> title) {
             mTitle = title;
             return this;
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index dfabe69..9cd4aec 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -244,11 +244,12 @@
         mPreviewClocks.reloadCurrentClock();
         mListeners.forEach((listener, clocks) -> {
             clocks.reloadCurrentClock();
-            ClockPlugin clock = clocks.getCurrentClock();
-            if (clock instanceof DefaultClockController) {
-                listener.onClockChanged(null);
+            final ClockPlugin clock = clocks.getCurrentClock();
+            if (Looper.myLooper() == Looper.getMainLooper()) {
+                listener.onClockChanged(clock instanceof DefaultClockController ? null : clock);
             } else {
-                listener.onClockChanged(clock);
+                mMainHandler.post(() -> listener.onClockChanged(
+                        clock instanceof DefaultClockController ? null : clock));
             }
         });
     }
@@ -323,7 +324,7 @@
             mClocks.put(plugin.getClass().getName(), plugin);
             mClockInfo.add(ClockInfo.builder()
                     .setName(plugin.getName())
-                    .setTitle(plugin.getTitle())
+                    .setTitle(plugin::getTitle)
                     .setId(id)
                     .setThumbnail(plugin::getThumbnail)
                     .setPreview(() -> plugin.getPreview(mWidth, mHeight))
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 6821265..dd38a33 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -124,6 +124,7 @@
 import com.android.systemui.util.leak.LeakReporter;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 import com.android.systemui.wm.DisplayWindowController;
+import com.android.systemui.wm.SystemWindows;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -323,6 +324,7 @@
     @Inject Lazy<Recents> mRecents;
     @Inject Lazy<StatusBar> mStatusBar;
     @Inject Lazy<DisplayWindowController> mDisplayWindowController;
+    @Inject Lazy<SystemWindows> mSystemWindows;
 
     @Inject
     public Dependency() {
@@ -513,6 +515,7 @@
         mProviders.put(Recents.class, mRecents::get);
         mProviders.put(StatusBar.class, mStatusBar::get);
         mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
+        mProviders.put(SystemWindows.class, mSystemWindows::get);
 
         // TODO(b/118592525): to support multi-display , we start to add something which is
         //                    per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index ab7eec5..9ce277e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -495,6 +495,7 @@
             lp.gravity = Gravity.TOP | Gravity.LEFT;
         }
         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        lp.setFitWindowInsetsTypes(0 /* types */);
         if (isLandscape(mRotation)) {
             lp.width = WRAP_CONTENT;
             lp.height = MATCH_PARENT;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index 79d4f8d..659629b 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -70,6 +70,7 @@
                             | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
                     PixelFormat.TRANSLUCENT);
             lp.setTitle("AssistDisclosure");
+            lp.setFitWindowInsetsTypes(0 /* types */);
 
             mWm.addView(mView, lp);
             mViewAdded = true;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 4cb1708..eb615a0 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -85,6 +85,7 @@
                 PixelFormat.TRANSLUCENT);
         mLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
         mLayoutParams.gravity = Gravity.BOTTOM;
+        mLayoutParams.setFitWindowInsetsTypes(0 /* types */);
         mLayoutParams.setTitle("Assist");
 
         mInvocationLightsView = (InvocationLightsView)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 3948416..36c89fd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -35,6 +35,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
@@ -590,6 +591,7 @@
         lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("BiometricPrompt");
         lp.token = windowToken;
+        lp.setFitWindowInsetsTypes(lp.getFitWindowInsetsTypes() & ~Type.statusBars());
         return lp;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index db5ff3f1..1277736 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -1119,36 +1119,33 @@
     }
 
     private void sendScreenshotToBubble(Bubble bubble) {
-        // delay allows the bubble menu to disappear before the screenshot
-        // done here because we already have a Handler to delay with.
-        // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying.
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                mScreenshotHelper.takeScreenshot(
-                        android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
-                        true /* hasStatus */,
-                        true /* hasNav */,
-                        mHandler,
-                        new Consumer<Uri>() {
-                            @Override
-                            public void accept(Uri uri) {
-                                if (uri != null) {
-                                    NotificationEntry entry = bubble.getEntry();
-                                    Pair<RemoteInput, Notification.Action> pair = entry.getSbn()
-                                            .getNotification().findRemoteInputActionPair(false);
-                                    RemoteInput remoteInput = pair.first;
-                                    Notification.Action action = pair.second;
-                                    Intent dataIntent = prepareRemoteInputFromData("image/png", uri,
-                                            remoteInput, entry);
-                                    sendRemoteInput(dataIntent, entry, action.actionIntent);
-                                    mBubbleData.setSelectedBubble(bubble);
-                                    mBubbleData.setExpanded(true);
-                                }
+        mScreenshotHelper.takeScreenshot(
+                android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
+                true /* hasStatus */,
+                true /* hasNav */,
+                mHandler,
+                new Consumer<Uri>() {
+                    @Override
+                    public void accept(Uri uri) {
+                        if (uri != null) {
+                            NotificationEntry entry = bubble.getEntry();
+                            Pair<RemoteInput, Notification.Action> pair = entry.getSbn()
+                                    .getNotification().findRemoteInputActionPair(false);
+                            if (pair != null) {
+                                RemoteInput remoteInput = pair.first;
+                                Notification.Action action = pair.second;
+                                Intent dataIntent = prepareRemoteInputFromData("image/png", uri,
+                                        remoteInput, entry);
+                                sendRemoteInput(dataIntent, entry, action.actionIntent);
+                                mBubbleData.setSelectedBubble(bubble);
+                                mBubbleData.setExpanded(true);
+                            } else {
+                                Log.w(TAG, "No RemoteInput found for notification: "
+                                        + entry.getSbn().getKey());
                             }
-                        });
-            }
-        }, 200);
+                        }
+                    }
+                });
     }
 
     private final BubbleScreenshotListener mBubbleScreenshotListener =
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
index e8eb72e..bf83065 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
@@ -31,6 +31,9 @@
     private FrameLayout mMenu;
     private boolean mShowing = false;
 
+    /** Delay before taking a screenshot once the button is tapped to allow the menu time to hide.*/
+    public static final long SCREENSHOT_DELAY = 200;
+
     public BubbleMenuView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 29a4bb1..245b232 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1731,17 +1731,18 @@
      */
     public void showBubbleMenu() {
         PointF currentPos = mStackAnimationController.getStackPosition();
-        float yPos = currentPos.y;
-        float xPos = currentPos.x;
-        if (mStackAnimationController.isStackOnLeftSide()) {
-            xPos += mBubbleSize;
-        } else {
-            //TODO: Use the width of the menu instead of this fixed offset. Offset used for now
-            // because menu width isn't correct the first time the menu is shown.
-            xPos -= mBubbleMenuOffset;
-        }
+        mBubbleMenuView.setVisibility(View.INVISIBLE);
+        post(() -> {
+            float yPos = currentPos.y;
+            float xPos = currentPos.x;
+            if (mStackAnimationController.isStackOnLeftSide()) {
+                xPos += mBubbleSize;
+            } else {
+                xPos -= mBubbleMenuView.getMenuView().getWidth();
+            }
 
-        mBubbleMenuView.show(xPos, yPos);
+            mBubbleMenuView.show(xPos, yPos);
+        });
     }
 
     /**
@@ -1762,6 +1763,12 @@
      * Take a screenshot and send it to the specified bubble.
      */
     public void sendScreenshotToBubble(Bubble bubble) {
-        mBubbleScreenshotListener.onBubbleScreenshot(bubble);
+        hideBubbleMenu();
+        // delay allows the bubble menu to disappear before the screenshot
+        // done here because we already have a Handler to delay with.
+        // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying.
+        postDelayed(() -> {
+            mBubbleScreenshotListener.onBubbleScreenshot(bubble);
+        }, BubbleMenuView.SCREENSHOT_DELAY);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index b1d205c..995b35f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -64,6 +64,7 @@
     private boolean mMovedEnough;
     private int mTouchSlopSquared;
     private VelocityTracker mVelocityTracker;
+    private Runnable mShowBubbleMenuRunnable;
 
     /** View that was initially touched, when we received the first ACTION_DOWN event. */
     private View mTouchedView;
@@ -133,6 +134,11 @@
                 if (isStack) {
                     mViewPositionOnTouchDown.set(mStack.getStackPosition());
                     mStack.onDragStart();
+                    if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()) {
+                        mShowBubbleMenuRunnable = mStack::showBubbleMenu;
+                        mStack.postDelayed(mShowBubbleMenuRunnable,
+                                ViewConfiguration.getLongPressTimeout());
+                    }
                 } else if (isFlyout) {
                     mStack.onFlyoutDragStart();
                 } else {
@@ -156,6 +162,7 @@
                 }
 
                 if (mMovedEnough) {
+                    mStack.removeCallbacks(mShowBubbleMenuRunnable);
                     if (isStack) {
                         mStack.onDragged(viewX, viewY);
                     } else if (isFlyout) {
@@ -163,13 +170,6 @@
                     } else {
                         mStack.onBubbleDragged(mTouchedView, viewX, viewY);
                     }
-                } else {
-                    float touchTime = event.getEventTime() - event.getDownTime();
-                    if (touchTime > ViewConfiguration.getLongPressTimeout() && !mStack.isExpanded()
-                            && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) {
-                        mStack.showBubbleMenu();
-                        return true;
-                    }
                 }
 
                 final boolean currentlyInDismissTarget = mStack.isInDismissTarget(event);
@@ -196,6 +196,8 @@
                 if (mStack.isShowingBubbleMenu()) {
                     resetForNextGesture();
                     return true;
+                } else {
+                    mStack.removeCallbacks(mShowBubbleMenuRunnable);
                 }
                 trackMovement(event);
                 mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 63a7771..ef853e6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1562,6 +1562,7 @@
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+            window.setFitWindowInsetsTypes(0 /* types */);
             setTitle(R.string.global_actions);
 
             mPanelController = plugin;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 53053fc..d385123 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -120,6 +120,7 @@
         window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
         window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+        window.setFitWindowInsetsTypes(0 /* types */);
         window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         window.addFlags(
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
index 3f15966..750cc60 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
@@ -109,6 +109,7 @@
             lp.setTitle("pip-dismiss-overlay");
             lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
             lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+            lp.setFitWindowInsetsTypes(0 /* types */);
             mWindowManager.addView(mDismissView, lp);
         }
         mDismissView.animate().cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index feb10a2..db52e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -177,7 +177,7 @@
                 record.tile.removeCallback(record.callback);
             }
             mTileLayout = mMediaTileLayout;
-            setTiles(mHost.getTiles());
+            if (mHost != null) setTiles(mHost.getTiles());
             mTileLayout.setListening(mListening);
             return true;
         } else if (!mMediaPlayer.hasMediaSession()
@@ -190,7 +190,7 @@
                 record.tile.removeCallback(record.callback);
             }
             mTileLayout = mRegularTileLayout;
-            setTiles(mHost.getTiles());
+            if (mHost != null) setTiles(mHost.getTiles());
             mTileLayout.setListening(mListening);
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index e0f26cd..1d37911 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -413,6 +413,7 @@
             handleSetListening(false);
         }
         mCallbacks.clear();
+        mHandler.removeCallbacksAndMessages(null);
     }
 
     protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index d819b8e..1d649ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -138,6 +138,7 @@
         lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("ScreenPinningConfirmation");
         lp.gravity = Gravity.FILL;
+        lp.setFitWindowInsetsTypes(0 /* types */);
         return lp;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 5041354..00220ce 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -258,6 +258,7 @@
                 PixelFormat.TRANSLUCENT);
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
         mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        mWindowLayoutParams.setFitWindowInsetsTypes(0 /* types */);
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mNotificationManager =
                 (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index bb34a87..f2b4ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -23,6 +23,7 @@
 import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -40,12 +41,14 @@
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver.InternalInsetsInfo;
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
 import android.view.WindowInsets;
@@ -321,6 +324,16 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if (isAttachedToWindow()
+                && ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL) {
+            // Our window doesn't cover entire display, so we use the display frame to re-calculate
+            // the insets.
+            final InsetsState state = getWindowInsetsController().getState();
+            insets = state.calculateInsets(state.getDisplayFrame(), insets.isRound(),
+                    insets.shouldAlwaysConsumeSystemBars(), insets.getDisplayCutout(),
+                    null /* legacyContentInsets */, null /* legacyStableInsets */,
+                    SOFT_INPUT_ADJUST_NOTHING, null /* typeSideMap */);
+        }
         if (mStableInsets.left != insets.getStableInsetLeft()
                 || mStableInsets.top != insets.getStableInsetTop()
                 || mStableInsets.right != insets.getStableInsetRight()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
deleted file mode 100644
index 1ac8198..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUpdateHandler.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-
-/**
- * Interface for accepting notification updates from {@link NotificationListener}.
- */
-public interface NotificationUpdateHandler {
-    /**
-     * Add a new notification and update the current notification ranking map.
-     *
-     * @param notification Notification to add
-     * @param ranking RankingMap to update with
-     */
-    void addNotification(StatusBarNotification notification,
-            NotificationListenerService.RankingMap ranking);
-
-    /**
-     * Remove a notification and update the current notification ranking map.
-     *
-     * @param key Key identifying the notification to remove
-     * @param ranking RankingMap to update with
-     * @param reason why the notification is being removed, e.g.
-     * {@link NotificationListenerService#REASON_CANCEL}.
-     */
-    void removeNotification(String key, NotificationListenerService.RankingMap ranking, int reason);
-
-    /**
-     * Update a given notification and the current notification ranking map.
-     *
-     * @param notification Updated notification
-     * @param ranking RankingMap to update with
-     */
-    void updateNotification(StatusBarNotification notification,
-            NotificationListenerService.RankingMap ranking);
-
-    /**
-     * Update with a new notification ranking map.
-     *
-     * @param ranking RankingMap to update with
-     */
-    void updateNotificationRanking(NotificationListenerService.RankingMap ranking);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index d81743a..dbefc7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -37,7 +37,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.NotificationUiAdjustment;
-import com.android.systemui.statusbar.NotificationUpdateHandler;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
@@ -94,7 +93,6 @@
 public class NotificationEntryManager implements
         Dumpable,
         NotificationContentInflater.InflationCallback,
-        NotificationUpdateHandler,
         VisualStabilityManager.Callback {
     private static final String TAG = "NotificationEntryMgr";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -346,7 +344,6 @@
     }
 
 
-    @Override
     public void removeNotification(String key, RankingMap ranking,
             int reason) {
         removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
@@ -506,7 +503,6 @@
         }
     }
 
-    @Override
     public void addNotification(StatusBarNotification notification, RankingMap ranking) {
         try {
             addNotificationInternal(notification, ranking);
@@ -556,7 +552,6 @@
         }
     }
 
-    @Override
     public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
         try {
             updateNotificationInternal(notification, ranking);
@@ -576,7 +571,6 @@
         }
     }
 
-    @Override
     public void updateNotificationRanking(RankingMap rankingMap) {
         List<NotificationEntry> entries = new ArrayList<>();
         entries.addAll(getVisibleNotifications());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
index 4f03003..efcef71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
@@ -31,6 +31,11 @@
     abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
 
     @Binds
+    abstract fun peopleHubSettingChangeDataSource(
+        impl: PeopleHubSettingChangeDataSourceImpl
+    ): DataSource<Boolean>
+
+    @Binds
     abstract fun peopleHubViewModelFactoryDataSource(
         impl: PeopleHubViewModelFactoryDataSourceImpl
     ): DataSource<PeopleHubViewModelFactory>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index 5c35408..e9d6a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -16,7 +16,14 @@
 
 package com.android.systemui.statusbar.notification.people
 
+import android.content.Context
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
 import android.view.View
+import com.android.systemui.dagger.qualifiers.MainHandler
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager
 import javax.inject.Inject
@@ -90,29 +97,58 @@
 @Singleton
 class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
     private val activityStarter: ActivityStarter,
-    private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>
+    private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>,
+    private val settingChangeSource: DataSource<@JvmSuppressWildcards Boolean>
 ) : DataSource<PeopleHubViewModelFactory> {
 
-    override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>) =
-            dataSource.registerListener(PeopleHubModelListenerImpl(activityStarter, listener))
+    override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>): Subscription {
+        var stripEnabled = false
+        var model: PeopleHubModel? = null
+
+        fun updateListener() {
+            // don't invoke listener until we've received our first model
+            model?.let { model ->
+                val factory =
+                        if (stripEnabled) PeopleHubViewModelFactoryImpl(model, activityStarter)
+                        else EmptyViewModelFactory
+                listener.onDataChanged(factory)
+            }
+        }
+
+        val settingSub = settingChangeSource.registerListener(object : DataListener<Boolean> {
+            override fun onDataChanged(data: Boolean) {
+                stripEnabled = data
+                updateListener()
+            }
+        })
+        val dataSub = dataSource.registerListener(object : DataListener<PeopleHubModel> {
+            override fun onDataChanged(data: PeopleHubModel) {
+                model = data
+                updateListener()
+            }
+        })
+        return object : Subscription {
+            override fun unsubscribe() {
+                settingSub.unsubscribe()
+                dataSub.unsubscribe()
+            }
+        }
+    }
 }
 
-private class PeopleHubModelListenerImpl(
-    private val activityStarter: ActivityStarter,
-    private val dataListener: DataListener<PeopleHubViewModelFactory>
-) : DataListener<PeopleHubModel> {
-
-    override fun onDataChanged(data: PeopleHubModel) =
-            dataListener.onDataChanged(PeopleHubViewModelFactoryImpl(data, activityStarter))
+private object EmptyViewModelFactory : PeopleHubViewModelFactory {
+    override fun createWithAssociatedClickView(view: View): PeopleHubViewModel {
+        return PeopleHubViewModel(emptySequence(), false)
+    }
 }
 
 private class PeopleHubViewModelFactoryImpl(
-    private val data: PeopleHubModel,
+    private val model: PeopleHubModel,
     private val activityStarter: ActivityStarter
 ) : PeopleHubViewModelFactory {
 
     override fun createWithAssociatedClickView(view: View): PeopleHubViewModel {
-        val personViewModels = data.people.asSequence().map { personModel ->
+        val personViewModels = model.people.asSequence().map { personModel ->
             val onClick = {
                 activityStarter.startPendingIntentDismissingKeyguard(
                         personModel.clickIntent,
@@ -122,7 +158,42 @@
             }
             PersonViewModel(personModel.name, personModel.avatar, onClick)
         }
-        return PeopleHubViewModel(personViewModels, data.people.isNotEmpty())
+        return PeopleHubViewModel(personViewModels, model.people.isNotEmpty())
+    }
+}
+
+@Singleton
+class PeopleHubSettingChangeDataSourceImpl @Inject constructor(
+    @MainHandler private val handler: Handler,
+    context: Context
+) : DataSource<Boolean> {
+
+    private val settingUri = Settings.Secure.getUriFor(Settings.Secure.PEOPLE_STRIP)
+    private val contentResolver = context.contentResolver
+
+    override fun registerListener(listener: DataListener<Boolean>): Subscription {
+        // Immediately report current value of setting
+        updateListener(listener)
+        val observer = object : ContentObserver(handler) {
+            override fun onChange(selfChange: Boolean, uri: Uri?, userId: Int) {
+                super.onChange(selfChange, uri, userId)
+                updateListener(listener)
+            }
+        }
+        contentResolver.registerContentObserver(settingUri, false, observer, UserHandle.USER_ALL)
+        return object : Subscription {
+            override fun unsubscribe() = contentResolver.unregisterContentObserver(observer)
+        }
+    }
+
+    private fun updateListener(listener: DataListener<Boolean>) {
+        val setting = Settings.Secure.getIntForUser(
+                contentResolver,
+                Settings.Secure.PEOPLE_STRIP,
+                0,
+                UserHandle.USER_CURRENT
+        )
+        listener.onDataChanged(setting != 0)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 782aad1..315ea0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -34,6 +34,7 @@
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.Window
+import android.view.WindowInsets.Type
 import android.view.WindowManager
 import android.widget.TextView
 import com.android.internal.annotations.VisibleForTesting
@@ -287,6 +288,7 @@
                 setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
                 addFlags(wmFlags)
                 setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL)
+                setFitWindowInsetsTypes(getFitWindowInsetsTypes() and Type.statusBars().inv())
                 setWindowAnimations(com.android.internal.R.style.Animation_InputMethod)
 
                 attributes = attributes.apply {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 8e9a051e..2761689 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -249,10 +249,8 @@
             }
         }
 
-        if (adjustPeopleHubVisibilityAndPosition(lastPersonIndex)) {
-            // make room for peopleHub
-            firstGentleNotifIndex++;
-        }
+        // make room for peopleHub
+        firstGentleNotifIndex += adjustPeopleHubVisibilityAndPosition(lastPersonIndex);
 
         adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
 
@@ -296,7 +294,7 @@
         }
     }
 
-    private boolean adjustPeopleHubVisibilityAndPosition(int lastPersonIndex) {
+    private int adjustPeopleHubVisibilityAndPosition(int lastPersonIndex) {
         final boolean showPeopleHeader = mPeopleHubVisible
                 && mNumberOfSections > 2
                 && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
@@ -307,6 +305,7 @@
         if (!showPeopleHeader) {
             if (currentlyVisible) {
                 mParent.removeView(mPeopleHubView);
+                return -1;
             }
         } else {
             mPeopleHubView.unDismiss();
@@ -317,7 +316,7 @@
                     mPeopleHubView.setTransientContainer(null);
                 }
                 mParent.addView(mPeopleHubView, targetIndex);
-                return true;
+                return 1;
             } else if (currentHubIndex != targetIndex) {
                 if (currentHubIndex < targetIndex) {
                     targetIndex--;
@@ -325,7 +324,7 @@
                 mParent.changeViewPosition(mPeopleHubView, targetIndex);
             }
         }
-        return false;
+        return 0;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 8ee964f..f25f910 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -300,6 +300,7 @@
         layoutParams.setTitle(TAG + mContext.getDisplayId());
         layoutParams.accessibilityTitle = mContext.getString(R.string.nav_bar_edge_panel);
         layoutParams.windowAnimations = 0;
+        layoutParams.setFitWindowInsetsTypes(0 /* types */);
         return layoutParams;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
index a784984..783e7ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
@@ -84,6 +84,7 @@
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("FloatingRotationButton");
+        lp.setFitWindowInsetsTypes(0 /*types */);
         switch (mWindowManager.getDefaultDisplay().getRotation()) {
             case Surface.ROTATION_0:
                 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 2ecceba..f94b2ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -204,6 +204,7 @@
                 PixelFormat.TRANSLUCENT);
         mLp.token = new Binder();
         mLp.gravity = Gravity.TOP;
+        mLp.setFitWindowInsetsTypes(0 /* types */);
         mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
         mLp.setTitle("StatusBar");
         mLp.packageName = mContext.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 44be6bc..28b6c38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -23,6 +23,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.UserHandle;
+import android.view.Window;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
@@ -102,16 +104,22 @@
 
     public static void setWindowOnTop(Dialog dialog) {
         if (Dependency.get(KeyguardStateController.class).isShowing()) {
-            dialog.getWindow().setType(LayoutParams.TYPE_STATUS_BAR_PANEL);
+            final Window window = dialog.getWindow();
+            window.setType(LayoutParams.TYPE_STATUS_BAR_PANEL);
+            window.setFitWindowInsetsTypes(
+                    window.getFitWindowInsetsTypes() & ~Type.statusBars());
         } else {
             dialog.getWindow().setType(LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
         }
     }
 
     public static AlertDialog applyFlags(AlertDialog dialog) {
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
-        dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+        final Window window = dialog.getWindow();
+        window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
+        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        window.setFitWindowInsetsTypes(
+                    window.getFitWindowInsetsTypes() & ~Type.statusBars());
         return dialog;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
new file mode 100644
index 0000000..5ec61c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -0,0 +1,330 @@
+/*
+ * 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.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DragEvent;
+import android.view.IWindow;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowlessViewRoot;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.HashMap;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Represents the "windowing" layer of the System-UI. This layer allows system-ui components to
+ * place and manipulate windows without talking to WindowManager.
+ */
+@Singleton
+public class SystemWindows {
+    private static final String TAG = "SystemWindows";
+
+    private final SparseArray<PerDisplay> mPerDisplay = new SparseArray<>();
+    final HashMap<View, WindowlessViewRoot> mViewRoots = new HashMap<>();
+    Context mContext;
+    IWindowSession mSession;
+    DisplayWindowController mDisplayController;
+    IWindowManager mWmService;
+
+    private final DisplayWindowController.DisplayWindowListener mDisplayListener =
+            new DisplayWindowController.DisplayWindowListener() {
+                @Override
+                public void onDisplayAdded(int displayId) { }
+
+                @Override
+                public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+                    PerDisplay pd = mPerDisplay.get(displayId);
+                    if (pd == null) {
+                        return;
+                    }
+                    pd.updateConfiguration(newConfig);
+                }
+
+                @Override
+                public void onDisplayRemoved(int displayId) { }
+            };
+
+    @Inject
+    public SystemWindows(Context context, DisplayWindowController displayController,
+            IWindowManager wmService) {
+        mContext = context;
+        mWmService = wmService;
+        mDisplayController = displayController;
+        mDisplayController.addDisplayWindowListener(mDisplayListener);
+        try {
+            mSession = wmService.openSession(
+                    new IWindowSessionCallback.Stub() {
+                        @Override
+                        public void onAnimatorScaleChanged(float scale) {}
+                    });
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to create layer", e);
+        }
+    }
+
+    /**
+     * Adds a view to system-ui window management.
+     */
+    public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
+            int windowType) {
+        PerDisplay pd = mPerDisplay.get(displayId);
+        if (pd == null) {
+            pd = new PerDisplay(displayId);
+            mPerDisplay.put(displayId, pd);
+        }
+        pd.addView(view, attrs, windowType);
+    }
+
+    /**
+     * Removes a view from system-ui window management.
+     * @param view
+     */
+    public void removeView(View view) {
+        WindowlessViewRoot root = mViewRoots.remove(view);
+        root.die();
+    }
+
+    /**
+     * Updates the layout params of a view.
+     */
+    public void updateViewLayout(@NonNull View view, ViewGroup.LayoutParams params) {
+        WindowlessViewRoot root = mViewRoots.get(view);
+        if (root == null || !(params instanceof WindowManager.LayoutParams)) {
+            return;
+        }
+        view.setLayoutParams(params);
+        root.relayout((WindowManager.LayoutParams) params);
+    }
+
+    /**
+     * Adds a root for system-ui window management with no views. Only useful for IME.
+     */
+    public void addRoot(int displayId, int windowType) {
+        PerDisplay pd = mPerDisplay.get(displayId);
+        if (pd == null) {
+            pd = new PerDisplay(displayId);
+            mPerDisplay.put(displayId, pd);
+        }
+        pd.addRoot(windowType);
+    }
+
+    /**
+     * Get the IWindow token for a specific root.
+     *
+     * @param windowType A window type from {@link android.view.WindowManager}.
+     */
+    IWindow getWindow(int displayId, int windowType) {
+        PerDisplay pd = mPerDisplay.get(displayId);
+        if (pd == null) {
+            return null;
+        }
+        return pd.getWindow(windowType);
+    }
+
+    private class PerDisplay {
+        final int mDisplayId;
+        private final SparseArray<SysUiWindowManager> mWwms = new SparseArray<>();
+
+        PerDisplay(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
+            SysUiWindowManager wwm = addRoot(windowType);
+            if (wwm == null) {
+                Slog.e(TAG, "Unable to create systemui root");
+                return;
+            }
+            final Display display = mDisplayController.getDisplay(mDisplayId);
+            WindowlessViewRoot viewRoot = new WindowlessViewRoot(mContext, display, wwm);
+            attrs.flags |= FLAG_HARDWARE_ACCELERATED;
+            viewRoot.addView(view, attrs);
+            mViewRoots.put(view, viewRoot);
+        }
+
+        SysUiWindowManager addRoot(int windowType) {
+            SysUiWindowManager wwm = mWwms.get(windowType);
+            if (wwm != null) {
+                return wwm;
+            }
+            SurfaceControl rootSurface = null;
+            ContainerWindow win = new ContainerWindow();
+            try {
+                rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
+            } catch (RemoteException e) {
+            }
+            if (rootSurface == null) {
+                Slog.e(TAG, "Unable to get root surfacecontrol for systemui");
+                return null;
+            }
+            Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
+            wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
+            mWwms.put(windowType, wwm);
+            return wwm;
+        }
+
+        IWindow getWindow(int windowType) {
+            SysUiWindowManager wwm = mWwms.get(windowType);
+            if (wwm == null) {
+                return null;
+            }
+            return wwm.mContainerWindow;
+        }
+
+        void updateConfiguration(Configuration configuration) {
+            for (int i = 0; i < mWwms.size(); ++i) {
+                mWwms.valueAt(i).updateConfiguration(configuration);
+            }
+        }
+    }
+
+    /**
+     * A subclass of WindowlessWindowManager that provides insets to its viewroots.
+     */
+    public class SysUiWindowManager extends WindowlessWindowManager {
+        final int mDisplayId;
+        ContainerWindow mContainerWindow;
+        public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
+                ContainerWindow container) {
+            super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
+            mContainerWindow = container;
+            mDisplayId = displayId;
+        }
+
+        @Override
+        public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+                int requestedWidth, int requestedHeight, int viewVisibility, int flags,
+                long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
+                Rect outVisibleInsets, Rect outStableInsets,
+                DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+                SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
+            int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+                    viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
+                    outContentInsets, outVisibleInsets, outStableInsets,
+                    cutout, mergedConfiguration, outSurfaceControl, outInsetsState);
+            if (res != 0) {
+                return res;
+            }
+            DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
+            outStableInsets.set(dl.stableInsets());
+            return 0;
+        }
+
+        void updateConfiguration(Configuration configuration) {
+            setConfiguration(configuration);
+        }
+    }
+
+    class ContainerWindow extends IWindow.Stub {
+        ContainerWindow() {}
+
+        @Override
+        public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
+                boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
+                boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+                DisplayCutout.ParcelableWrapper displayCutout) {}
+
+        @Override
+        public void locationInParentDisplayChanged(Point offset) {}
+
+        @Override
+        public void insetsChanged(InsetsState insetsState) {}
+
+        @Override
+        public void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {}
+
+        @Override
+        public void showInsets(int types, boolean fromIme) {}
+
+        @Override
+        public void hideInsets(int types, boolean fromIme) {}
+
+        @Override
+        public void moved(int newX, int newY) {}
+
+        @Override
+        public void dispatchAppVisibility(boolean visible) {}
+
+        @Override
+        public void dispatchGetNewSurface() {}
+
+        @Override
+        public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {}
+
+        @Override
+        public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {}
+
+        @Override
+        public void closeSystemDialogs(String reason) {}
+
+        @Override
+        public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+                boolean sync) {}
+
+        @Override
+        public void dispatchWallpaperCommand(String action, int x, int y,
+                int z, Bundle extras, boolean sync) {}
+
+        /* Drag/drop */
+        @Override
+        public void dispatchDragEvent(DragEvent event) {}
+
+        @Override
+        public void updatePointerIcon(float x, float y) {}
+
+        @Override
+        public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
+                int localValue, int localChanges) {}
+
+        @Override
+        public void dispatchWindowShown() {}
+
+        @Override
+        public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
+
+        @Override
+        public void dispatchPointerCaptureChanged(boolean hasCapture) {}
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
index d2b2654..4c0890a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockInfoTest.java
@@ -57,7 +57,7 @@
     @Test
     public void testGetTitle() {
         final String title = "title";
-        ClockInfo info = ClockInfo.builder().setTitle(title).build();
+        ClockInfo info = ClockInfo.builder().setTitle(() -> title).build();
         assertThat(info.getTitle()).isEqualTo(title);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
index 0cd6f9a..d2832fb9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockOptionsProviderTest.java
@@ -117,12 +117,12 @@
     public void testQuery_listOptions() {
         mClocks.add(ClockInfo.builder()
                 .setName("name_a")
-                .setTitle("title_a")
+                .setTitle(() -> "title_a")
                 .setId("id_a")
                 .build());
         mClocks.add(ClockInfo.builder()
                 .setName("name_b")
-                .setTitle("title_b")
+                .setTitle(() -> "title_b")
                 .setId("id_b")
                 .build());
         Cursor cursor = mProvider.query(mListOptionsUri, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 192d8f8..49b47c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -188,6 +188,16 @@
         verify(mTile).handleSetListening(eq(false));
     }
 
+    @Test
+    public void testHandleDestroyClearsHandlerQueue() {
+        when(mTile.getStaleTimeout()).thenReturn(0L);
+        mTile.handleRefreshState(null); // this will add a delayed H.STALE message
+        mTile.handleDestroy();
+
+        mTestableLooper.processAllMessages();
+        verify(mTile, never()).handleStale();
+    }
+
     private class TileLogMatcher implements ArgumentMatcher<LogMaker> {
 
         private final int mCategory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index f5d6f22..0764d0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -89,8 +89,17 @@
                 return mockSubscription
             }
         }
+        val fakeSettingDataSource = object : DataSource<Boolean> {
+            override fun registerListener(listener: DataListener<Boolean>): Subscription {
+                listener.onDataChanged(true)
+                return mockSubscription
+            }
+        }
         val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
-                mockActivityStarter, fakeModelDataSource)
+                mockActivityStarter,
+                fakeModelDataSource,
+                fakeSettingDataSource
+        )
         val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
         val mockClickView = mock(View::class.java)
 
@@ -112,6 +121,41 @@
                 same(mockClickView)
         )
     }
+
+    @Test
+    fun testViewModelDataSource_notVisibleIfSettingDisabled() {
+        val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
+        val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
+        val fakeModel = PeopleHubModel(listOf(fakePerson))
+        val mockSubscription = mock(Subscription::class.java)
+        val fakeModelDataSource = object : DataSource<PeopleHubModel> {
+            override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
+                listener.onDataChanged(fakeModel)
+                return mockSubscription
+            }
+        }
+        val fakeSettingDataSource = object : DataSource<Boolean> {
+            override fun registerListener(listener: DataListener<Boolean>): Subscription {
+                listener.onDataChanged(false)
+                return mockSubscription
+            }
+        }
+        val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
+                mockActivityStarter,
+                fakeModelDataSource,
+                fakeSettingDataSource
+        )
+        val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
+        val mockClickView = mock(View::class.java)
+
+        factoryDataSource.registerListener(fakeListener)
+
+        val viewModel = (fakeListener.lastSeen as Maybe.Just).value
+                .createWithAssociatedClickView(mockClickView)
+        assertThat(viewModel.isVisible).isFalse()
+        val people = viewModel.people.toList()
+        assertThat(people.size).isEqualTo(0)
+    }
 }
 
 /** Works around Mockito matchers returning `null` and breaking non-nullable Kotlin code. */
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index eb0d443..7fb286b 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -17,6 +17,7 @@
 
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -175,6 +176,10 @@
      */
     @Deprecated
     public int tether(@NonNull String iface) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return TETHER_ERROR_SERVICE_UNAVAIL;
+        }
         try {
             mConnector.tether(iface);
         } catch (RemoteException e) {
@@ -191,6 +196,10 @@
      */
     @Deprecated
     public int untether(@NonNull String iface) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return TETHER_ERROR_SERVICE_UNAVAIL;
+        }
         try {
             mConnector.untether(iface);
         } catch (RemoteException e) {
@@ -210,6 +219,10 @@
      */
     @Deprecated
     public int setUsbTethering(boolean enable) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return TETHER_ERROR_SERVICE_UNAVAIL;
+        }
         try {
             mConnector.setUsbTethering(enable);
         } catch (RemoteException e) {
@@ -227,6 +240,10 @@
     // TODO: improve the usage of ResultReceiver, b/145096122
     public void startTethering(int type, @NonNull ResultReceiver receiver,
             boolean showProvisioningUi) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return;
+        }
         try {
             mConnector.startTethering(type, receiver, showProvisioningUi);
         } catch (RemoteException e) {
@@ -241,6 +258,10 @@
      * {@hide}
      */
     public void stopTethering(int type) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return;
+        }
         try {
             mConnector.stopTethering(type);
         } catch (RemoteException e) {
@@ -258,6 +279,10 @@
     // TODO: improve the usage of ResultReceiver, b/145096122
     public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver,
             boolean showEntitlementUi) {
+        if (mConnector == null) {
+            Slog.wtf(TAG, "Tethering not ready yet");
+            return;
+        }
         try {
             mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
         } catch (RemoteException e) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 7c78ef8..743fd6a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -456,7 +456,7 @@
                     mLog.e("setWifiTethering: failed to get WifiManager!");
                     return TETHER_ERROR_SERVICE_UNAVAIL;
                 }
-                if ((enable && mgr.startSoftAp(null /* use existing wifi config */))
+                if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
                         || (!enable && mgr.stopSoftAp())) {
                     mWifiTetherRequested = enable;
                     return TETHER_ERROR_NO_ERROR;
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 0273ed3..cdbc541 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -94,7 +94,7 @@
 import android.net.util.InterfaceParams;
 import android.net.util.NetworkConstants;
 import android.net.util.SharedLog;
-import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiManager;
 import android.net.wifi.p2p.WifiP2pGroup;
 import android.net.wifi.p2p.WifiP2pInfo;
@@ -806,12 +806,12 @@
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failingWifiTetheringLegacyApBroadcast() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
         mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
+        verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mNMService);
 
@@ -833,12 +833,12 @@
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
         mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
+        verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mNMService);
 
@@ -907,13 +907,13 @@
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failureEnablingIpForwarding() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
         doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
 
         // Emulate pressing the WiFi tethering button.
         mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
+        verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mNMService);
 
@@ -1155,7 +1155,7 @@
         when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
         when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                 .thenReturn(upstreamState);
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
         mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
         mLooper.dispatchAll();
         tetherState = callback.pollTetherStatesChanged();
diff --git a/services/Android.bp b/services/Android.bp
index fd4094f..8376d2b 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -111,7 +111,7 @@
     srcs: [":services-sources"],
     installable: false,
     // TODO: remove the --hide options below
-    args: " --show-single-annotation android.annotation.SystemApi" +
+    args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.INTERNAL,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
         " --hide-annotation android.annotation.Hide" +
         " --hide-package com.google.android.startop.iorap" +
         " --hide ReferencesHidden" +
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 7e8edf2..26bb7c3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -465,7 +465,7 @@
 
         if (mCreateFillUiRunnable != null) {
             if (sDebug) Slog.d(TAG, "start the pending fill UI request..");
-            mCreateFillUiRunnable.run();
+            mHandler.post(mCreateFillUiRunnable);
             mCreateFillUiRunnable = null;
         }
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index e8c5299..3651a41 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -274,9 +274,14 @@
         }
     }
 
-    // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
-    // it's used in multiple places where I/O waits would cause system lock-ups.
-    private boolean isUserReadyForBackup(int userId) {
+    /**
+     * This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
+     * it's used in multiple places where I/O waits would cause system lock-ups.
+     * @param userId User id for which this operation should be performed.
+     * @return true if the user is ready for backup and false otherwise.
+     */
+    @Override
+    public boolean isUserReadyForBackup(int userId) {
         return mUserServices.get(UserHandle.USER_SYSTEM) != null
                 && mUserServices.get(userId) != null;
     }
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
index cbf2a62..bbcfdc6 100644
--- a/services/core/java/com/android/server/GnssManagerService.java
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -56,6 +56,7 @@
 import com.android.server.location.GnssMeasurementsProvider;
 import com.android.server.location.GnssNavigationMessageProvider;
 import com.android.server.location.GnssStatusListenerHelper;
+import com.android.server.location.LocationUsageLogger;
 import com.android.server.location.RemoteListenerHelper;
 
 import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 6300ab8..cad917b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -104,6 +104,7 @@
 import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
 import com.android.server.location.LocationSettingsStore;
+import com.android.server.location.LocationUsageLogger;
 import com.android.server.location.MockProvider;
 import com.android.server.location.PassiveProvider;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -158,21 +159,15 @@
         }
     }
 
-    private static final String TAG = "LocationManagerService";
+    public static final String TAG = "LocationManagerService";
     public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final String WAKELOCK_KEY = "*location*";
 
-    // Location resolution level: no location data whatsoever
     private static final int RESOLUTION_LEVEL_NONE = 0;
-    // Location resolution level: coarse location data only
     private static final int RESOLUTION_LEVEL_COARSE = 1;
-    // Location resolution level: fine location data
     private static final int RESOLUTION_LEVEL_FINE = 2;
 
-    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
-            android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
-
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
             "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
@@ -198,6 +193,8 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final Handler mHandler;
+    private final LocationSettingsStore mSettingsStore;
+    private final LocationUsageLogger mLocationUsageLogger;
 
     private AppOpsManager mAppOps;
     private PackageManager mPackageManager;
@@ -205,8 +202,6 @@
     private ActivityManager mActivityManager;
     private UserManager mUserManager;
 
-    private LocationSettingsStore mSettingsStore;
-
     private GeofenceManager mGeofenceManager;
     private LocationFudger mLocationFudger;
     private GeocoderProxy mGeocodeProvider;
@@ -219,12 +214,12 @@
 
     // list of currently active providers
     @GuardedBy("mLock")
-    private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
+    private final ArrayList<LocationProviderManager> mProviders = new ArrayList<>();
 
     // list of non-mock providers, so that when mock providers replace real providers, they can be
     // later re-replaced
     @GuardedBy("mLock")
-    private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
+    private final ArrayList<LocationProviderManager> mRealProviders = new ArrayList<>();
 
     @GuardedBy("mLock")
     private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
@@ -251,12 +246,10 @@
     @PowerManager.LocationPowerSaveMode
     private int mBatterySaverMode;
 
-    @GuardedBy("mLock")
-    private final LocationUsageLogger mLocationUsageLogger;
-
     private LocationManagerService(Context context) {
         mContext = context;
         mHandler = FgThread.getHandler();
+        mSettingsStore = new LocationSettingsStore(mContext, mHandler);
         mLocationUsageLogger = new LocationUsageLogger();
 
         // Let the package manager query which are the default location
@@ -274,6 +267,8 @@
     }
 
     private void onSystemReady() {
+        mSettingsStore.onSystemReady();
+
         synchronized (mLock) {
             mPackageManager = mContext.getPackageManager();
             mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -281,7 +276,6 @@
             mActivityManager = mContext.getSystemService(ActivityManager.class);
             mUserManager = mContext.getSystemService(UserManager.class);
 
-            mSettingsStore = new LocationSettingsStore(mContext, mHandler);
             mLocationFudger = new LocationFudger(mContext, mHandler);
             mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
 
@@ -421,14 +415,14 @@
         for (Receiver receiver : mReceivers.values()) {
             receiver.updateMonitoring(true);
         }
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             applyRequirementsLocked(p);
         }
     }
 
     @GuardedBy("mLock")
     private void onPermissionsChangedLocked() {
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             applyRequirementsLocked(p);
         }
     }
@@ -448,7 +442,7 @@
 
         mBatterySaverMode = newLocationMode;
 
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             applyRequirementsLocked(p);
         }
     }
@@ -456,7 +450,7 @@
     @GuardedBy("mLock")
     private void onScreenStateChangedLocked() {
         if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
-            for (LocationProvider p : mProviders) {
+            for (LocationProviderManager p : mProviders) {
                 applyRequirementsLocked(p);
             }
         }
@@ -472,7 +466,7 @@
         intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
         mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
 
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             p.onUseableChangedLocked(userId);
         }
     }
@@ -527,21 +521,21 @@
 
     @GuardedBy("mLock")
     private void onBackgroundThrottleIntervalChangedLocked() {
-        for (LocationProvider provider : mProviders) {
+        for (LocationProviderManager provider : mProviders) {
             applyRequirementsLocked(provider);
         }
     }
 
     @GuardedBy("mLock")
     private void onBackgroundThrottleWhitelistChangedLocked() {
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             applyRequirementsLocked(p);
         }
     }
 
     @GuardedBy("lock")
     private void onIgnoreSettingsWhitelistChangedLocked() {
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             applyRequirementsLocked(p);
         }
     }
@@ -630,14 +624,15 @@
     @GuardedBy("mLock")
     private void initializeProvidersLocked() {
         // create a passive location provider, which is always enabled
-        LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
+        LocationProviderManager passiveProviderManager = new LocationProviderManager(
+                PASSIVE_PROVIDER);
         addProviderLocked(passiveProviderManager);
         mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
         passiveProviderManager.attachLocked(mPassiveProvider);
 
         if (GnssManagerService.isGnssSupported()) {
             // Create a gps location provider manager
-            LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER);
+            LocationProviderManager gnssProviderManager = new LocationProviderManager(GPS_PROVIDER);
             mRealProviders.add(gnssProviderManager);
             addProviderLocked(gnssProviderManager);
 
@@ -668,7 +663,8 @@
         ensureFallbackFusedProviderPresentLocked(pkgs);
 
         // bind to network provider
-        LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER);
+        LocationProviderManager networkProviderManager = new LocationProviderManager(
+                NETWORK_PROVIDER);
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 networkProviderManager,
@@ -685,7 +681,7 @@
         }
 
         // bind to fused provider
-        LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
+        LocationProviderManager fusedProviderManager = new LocationProviderManager(FUSED_PROVIDER);
         LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 fusedProviderManager,
@@ -758,7 +754,7 @@
                     Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
                     Integer.parseInt(fragments[8]) /* powerRequirement */,
                     Integer.parseInt(fragments[9]) /* accuracy */);
-            LocationProvider testProviderManager = new LocationProvider(name);
+            LocationProviderManager testProviderManager = new LocationProviderManager(name);
             addProviderLocked(testProviderManager);
             testProviderManager.attachLocked(
                     new MockProvider(mContext, testProviderManager, properties));
@@ -780,7 +776,7 @@
         onUserProfilesChangedLocked();
 
         // let providers know the current user has changed
-        for (LocationProvider p : mProviders) {
+        for (LocationProviderManager p : mProviders) {
             p.onUseableChangedLocked(oldUserId);
             p.onUseableChangedLocked(mCurrentUserId);
         }
@@ -789,7 +785,7 @@
     /**
      * Location provider manager, manages a LocationProvider.
      */
-    class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
+    class LocationProviderManager implements AbstractLocationProvider.LocationProviderManager {
 
         private final String mName;
 
@@ -807,7 +803,7 @@
         @Nullable
         private ProviderProperties mProperties;
 
-        private LocationProvider(String name) {
+        private LocationProviderManager(String name) {
             mName = name;
 
             mProvider = null;
@@ -944,7 +940,7 @@
                 return;
             }
             synchronized (mLock) {
-                LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+                LocationProviderManager gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
                 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
                     Slog.w(TAG, "reportLocationBatch() called without user permission");
                     return;
@@ -1035,7 +1031,7 @@
         }
     }
 
-    private class MockLocationProvider extends LocationProvider {
+    private class MockLocationProvider extends LocationProviderManager {
 
         private ProviderRequest mCurrentRequest;
 
@@ -1185,7 +1181,8 @@
                 // See if receiver has any enabled update records.  Also note if any update records
                 // are high power (has a high power provider with an interval under a threshold).
                 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
-                    LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
+                    LocationProviderManager provider = getLocationProviderLocked(
+                            updateRecord.mProvider);
                     if (provider == null) {
                         continue;
                     }
@@ -1461,7 +1458,7 @@
     }
 
     @GuardedBy("mLock")
-    private void addProviderLocked(LocationProvider provider) {
+    private void addProviderLocked(LocationProviderManager provider) {
         Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
 
         mProviders.add(provider);
@@ -1472,7 +1469,7 @@
     }
 
     @GuardedBy("mLock")
-    private void removeProviderLocked(LocationProvider provider) {
+    private void removeProviderLocked(LocationProviderManager provider) {
         if (mProviders.remove(provider)) {
             // it would be more correct to call this for all users, but we know this can only
             // affect the current user since providers are disabled for non-current users
@@ -1482,8 +1479,8 @@
 
     @GuardedBy("mLock")
     @Nullable
-    private LocationProvider getLocationProviderLocked(String providerName) {
-        for (LocationProvider provider : mProviders) {
+    private LocationProviderManager getLocationProviderLocked(String providerName) {
+        for (LocationProviderManager provider : mProviders) {
             if (providerName.equals(provider.getName())) {
                 return provider;
             }
@@ -1534,7 +1531,7 @@
             // network and fused providers are ok with COARSE or FINE
             return RESOLUTION_LEVEL_COARSE;
         } else {
-            for (LocationProvider lp : mProviders) {
+            for (LocationProviderManager lp : mProviders) {
                 if (!lp.getName().equals(provider)) {
                     continue;
                 }
@@ -1634,7 +1631,7 @@
     public List<String> getAllProviders() {
         synchronized (mLock) {
             ArrayList<String> providers = new ArrayList<>(mProviders.size());
-            for (LocationProvider provider : mProviders) {
+            for (LocationProviderManager provider : mProviders) {
                 String name = provider.getName();
                 if (FUSED_PROVIDER.equals(name)) {
                     continue;
@@ -1655,7 +1652,7 @@
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         synchronized (mLock) {
             ArrayList<String> providers = new ArrayList<>(mProviders.size());
-            for (LocationProvider provider : mProviders) {
+            for (LocationProviderManager provider : mProviders) {
                 String name = provider.getName();
                 if (FUSED_PROVIDER.equals(name)) {
                     continue;
@@ -1705,7 +1702,7 @@
     }
 
     @GuardedBy("mLock")
-    private void updateProviderUseableLocked(LocationProvider provider) {
+    private void updateProviderUseableLocked(LocationProviderManager provider) {
         boolean useable = provider.isUseableLocked();
 
         ArrayList<Receiver> deadReceivers = null;
@@ -1744,14 +1741,14 @@
 
     @GuardedBy("mLock")
     private void applyRequirementsLocked(String providerName) {
-        LocationProvider provider = getLocationProviderLocked(providerName);
+        LocationProviderManager provider = getLocationProviderLocked(providerName);
         if (provider != null) {
             applyRequirementsLocked(provider);
         }
     }
 
     @GuardedBy("mLock")
-    private void applyRequirementsLocked(LocationProvider provider) {
+    private void applyRequirementsLocked(LocationProviderManager provider) {
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         WorkSource worksource = new WorkSource();
         ProviderRequest providerRequest = new ProviderRequest();
@@ -2201,7 +2198,7 @@
             throw new IllegalArgumentException("provider name must not be null");
         }
 
-        LocationProvider provider = getLocationProviderLocked(name);
+        LocationProviderManager provider = getLocationProviderLocked(name);
         if (provider == null) {
             throw new IllegalArgumentException("provider doesn't exist: " + name);
         }
@@ -2323,7 +2320,7 @@
                 // or use the fused provider
                 String name = request.getProvider();
                 if (name == null) name = LocationManager.FUSED_PROVIDER;
-                LocationProvider provider = getLocationProviderLocked(name);
+                LocationProviderManager provider = getLocationProviderLocked(name);
                 if (provider == null) return null;
 
                 // only the current user or location providers may get location this way
@@ -2453,7 +2450,7 @@
                 "Access Fine Location permission not granted to inject Location");
 
         synchronized (mLock) {
-            LocationProvider provider = getLocationProviderLocked(location.getProvider());
+            LocationProviderManager provider = getLocationProviderLocked(location.getProvider());
             if (provider == null || !provider.isUseableLocked()) {
                 return false;
             }
@@ -2624,6 +2621,10 @@
             // throw NullPointerException to remain compatible with previous implementation
             throw new NullPointerException();
         }
+
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
+
         synchronized (mLock) {
             checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
                     providerName);
@@ -2633,13 +2634,7 @@
                     LocationStatsEnums.API_SEND_EXTRA_COMMAND,
                     providerName);
 
-            // and check for ACCESS_LOCATION_EXTRA_COMMANDS
-            if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
-                    != PERMISSION_GRANTED)) {
-                throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
-            }
-
-            LocationProvider provider = getLocationProviderLocked(providerName);
+            LocationProviderManager provider = getLocationProviderLocked(providerName);
             if (provider != null) {
                 provider.sendExtraCommand(command, extras);
             }
@@ -2662,7 +2657,7 @@
     @Override
     public ProviderProperties getProviderProperties(String providerName) {
         synchronized (mLock) {
-            LocationProvider provider = getLocationProviderLocked(providerName);
+            LocationProviderManager provider = getLocationProviderLocked(providerName);
             if (provider == null) {
                 return null;
             }
@@ -2675,7 +2670,7 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
                 Manifest.permission.READ_DEVICE_CONFIG + " permission required");
         synchronized (mLock) {
-            for (LocationProvider provider : mProviders) {
+            for (LocationProviderManager provider : mProviders) {
                 if (provider.getPackagesLocked().contains(packageName)) {
                     return true;
                 }
@@ -2689,7 +2684,7 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
                 Manifest.permission.READ_DEVICE_CONFIG + " permission required");
         synchronized (mLock) {
-            LocationProvider provider = getLocationProviderLocked(providerName);
+            LocationProviderManager provider = getLocationProviderLocked(providerName);
             return provider == null ? Collections.emptyList() : provider.getPackagesLocked();
         }
     }
@@ -2758,7 +2753,7 @@
         if (FUSED_PROVIDER.equals(providerName)) return false;
 
         synchronized (mLock) {
-            LocationProvider provider = getLocationProviderLocked(providerName);
+            LocationProviderManager provider = getLocationProviderLocked(providerName);
             return provider != null && provider.isUseableLocked(userId);
         }
     }
@@ -2797,7 +2792,7 @@
     }
 
     @GuardedBy("mLock")
-    private void handleLocationChangedLocked(Location location, LocationProvider provider) {
+    private void handleLocationChangedLocked(Location location, LocationProviderManager provider) {
         if (!mProviders.contains(provider)) {
             return;
         }
@@ -3029,7 +3024,7 @@
         synchronized (mLock) {
             long identity = Binder.clearCallingIdentity();
             try {
-                LocationProvider oldProvider = getLocationProviderLocked(name);
+                LocationProviderManager oldProvider = getLocationProviderLocked(name);
                 if (oldProvider != null) {
                     removeProviderLocked(oldProvider);
                 }
@@ -3053,7 +3048,7 @@
         synchronized (mLock) {
             long identity = Binder.clearCallingIdentity();
             try {
-                LocationProvider testProvider = getLocationProviderLocked(name);
+                LocationProviderManager testProvider = getLocationProviderLocked(name);
                 if (testProvider == null || !testProvider.isMock()) {
                     return;
                 }
@@ -3061,8 +3056,8 @@
                 removeProviderLocked(testProvider);
 
                 // reinstate real provider if available
-                LocationProvider realProvider = null;
-                for (LocationProvider provider : mRealProviders) {
+                LocationProviderManager realProvider = null;
+                for (LocationProviderManager provider : mRealProviders) {
                     if (name.equals(provider.getName())) {
                         realProvider = provider;
                         break;
@@ -3086,7 +3081,7 @@
         }
 
         synchronized (mLock) {
-            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            LocationProviderManager testProvider = getLocationProviderLocked(providerName);
             if (testProvider == null || !testProvider.isMock()) {
                 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
             }
@@ -3110,7 +3105,7 @@
         }
 
         synchronized (mLock) {
-            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            LocationProviderManager testProvider = getLocationProviderLocked(providerName);
             if (testProvider == null || !testProvider.isMock()) {
                 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
             }
@@ -3128,7 +3123,7 @@
         }
 
         synchronized (mLock) {
-            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            LocationProviderManager testProvider = getLocationProviderLocked(providerName);
             if (testProvider == null || !testProvider.isMock()) {
                 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
             }
@@ -3237,7 +3232,7 @@
 
             ipw.println("Location Providers:");
             ipw.increaseIndent();
-            for (LocationProvider provider : mProviders) {
+            for (LocationProviderManager provider : mProviders) {
                 provider.dumpLocked(fd, ipw, args);
             }
             ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 92d1da5..c0f10a3 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -16,8 +16,6 @@
 
 package com.android.server;
 
-import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-
 import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -39,7 +37,6 @@
 import android.os.UserHandle;
 import android.service.carrier.CarrierMessagingService;
 import android.telephony.SmsManager;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
@@ -526,11 +523,11 @@
 
                 // Grant permission for the carrier app.
                 Intent intent = new Intent(action);
-                TelephonyManager telephonyManager = (TelephonyManager)
-                        mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                List<String> carrierPackages = telephonyManager
-                        .getCarrierPackageNamesForIntentAndPhone(
-                                intent, getPhoneIdFromSubId(subId));
+                TelephonyManager telephonyManager =
+                        (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+                List<String> carrierPackages =
+                        telephonyManager.getCarrierPackageNamesForIntentAndPhone(
+                                intent, SubscriptionManager.getPhoneId(subId));
                 if (carrierPackages != null && carrierPackages.size() == 1) {
                     LocalServices.getService(UriGrantsManagerInternal.class)
                             .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
@@ -542,13 +539,4 @@
             return contentUri;
         }
     }
-
-    private int getPhoneIdFromSubId(int subId) {
-        SubscriptionManager subManager = (SubscriptionManager)
-                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        if (subManager == null) return INVALID_SIM_SLOT_INDEX;
-        SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
-        if (info == null) return INVALID_SIM_SLOT_INDEX;
-        return info.getSimSlotIndex();
-    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0a6473a..9b1d9e9 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1584,10 +1584,8 @@
         // Snapshot feature flag used for this boot
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
                 SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
-        SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
-                SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));
 
-        mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false);
+        mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);
         mContext = context;
         mResolver = mContext.getContentResolver();
         mCallbacks = new Callbacks(FgThread.get().getLooper());
@@ -1647,12 +1645,22 @@
      *  and updates PROP_FUSE (reboots if changed).
      */
     private void updateFusePropFromSettings() {
-        Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
-                + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
-        Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
-        if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+        String settingsFuseFlag = SystemProperties.get(StorageManager.PROP_SETTINGS_FUSE);
+        Slog.d(TAG, "The value of Settings Fuse Flag is "
+                + (settingsFuseFlag == null || settingsFuseFlag.isEmpty()
+                ? "null" : settingsFuseFlag));
+        // Set default value of PROP_SETTINGS_FUSE and PROP_FUSE if it
+        // is unset (neither true nor false, this happens only on the first boot
+        // after wiping data partition).
+        if (settingsFuseFlag == null || settingsFuseFlag.isEmpty()) {
+            SystemProperties.set(StorageManager.PROP_SETTINGS_FUSE, "false");
+            SystemProperties.set(StorageManager.PROP_FUSE, "false");
+            return;
+        }
+
+        if (!SystemProperties.get(StorageManager.PROP_FUSE).equals(settingsFuseFlag)) {
             Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
-            SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+            SystemProperties.set(StorageManager.PROP_FUSE, settingsFuseFlag);
             // Perform hard reboot to kick policy into place
             mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
                     + "property change to take effect");
@@ -3097,14 +3105,6 @@
 
     @Override
     public void mkdirs(String callingPkg, String appPath) {
-        if (mIsFuseEnabled) {
-            // TODO(b/144332951): Calling into Vold is risky because the FUSE daemon can go down
-            // anytime and Vold will hang forever. We should either remove this call
-            // or at least call into the FUSE daemon to mkdir instead
-            Slog.w(TAG, "Not making dir for package " + callingPkg + " with path " + appPath);
-            return;
-        }
-
         final int callingUid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(callingUid);
         final UserEnvironment userEnv = new UserEnvironment(userId);
@@ -3824,7 +3824,7 @@
                 }
             }
             if ((hasInstall || hasInstallOp) && hasWrite) {
-                return Zygote.MOUNT_EXTERNAL_WRITE;
+                return Zygote.MOUNT_EXTERNAL_INSTALLER;
             }
 
             // Otherwise we're willing to give out sandboxed or non-sandboxed if
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 1d24507..4a0c7a3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
 import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA;
 import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE;
@@ -60,7 +59,6 @@
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
@@ -99,7 +97,7 @@
  * and 15973975 by saving the phoneId of the registrant and then using the
  * phoneId when deciding to to make a callback. This is necessary because
  * a subId changes from to a dummy value when a SIM is removed and thus won't
- * compare properly. Because getPhoneIdFromSubId(int subId) handles
+ * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles
  * the dummy value conversion we properly do the callbacks.
  *
  * Eventually we may want to remove the notion of dummy value but for now this
@@ -133,7 +131,7 @@
 
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-        int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+        int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
         boolean matchPhoneStateListenerEvent(int events) {
             return (callback != null) && ((events & this.events) != 0);
@@ -233,7 +231,7 @@
 
     private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-    private int mDefaultPhoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+    private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
     private int[] mRingingCallState;
 
@@ -360,7 +358,7 @@
                         SubscriptionManager.getDefaultSubscriptionId());
                 int newDefaultPhoneId = intent.getIntExtra(
                         SubscriptionManager.EXTRA_SLOT_INDEX,
-                        getPhoneIdFromSubId(newDefaultSubId));
+                        SubscriptionManager.getPhoneId(newDefaultSubId));
                 if (DBG) {
                     log("onReceive:current mDefaultSubId=" + mDefaultSubId
                             + " current mDefaultPhoneId=" + mDefaultPhoneId
@@ -770,7 +768,7 @@
                 return;
             }
 
-            int phoneId = getPhoneIdFromSubId(subId);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
             synchronized (mRecords) {
                 // register
                 IBinder b = callback.asBinder();
@@ -1101,7 +1099,7 @@
         // Called only by Telecomm to communicate call state across different phone accounts. So
         // there is no need to add a valid subId or slotId.
         broadcastCallStateChanged(state, phoneNumber,
-                SubscriptionManager.INVALID_SIM_SLOT_INDEX,
+                SubscriptionManager.INVALID_PHONE_INDEX,
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
@@ -1326,7 +1324,7 @@
         synchronized (mRecords) {
             mCarrierNetworkChangeState = active;
             for (int subId : subIds) {
-                int phoneId = getPhoneIdFromSubId(subId);
+                int phoneId = SubscriptionManager.getPhoneId(subId);
 
                 if (VDBG) {
                     log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
@@ -1359,7 +1357,7 @@
             log("notifyCellInfoForSubscriber: subId=" + subId
                 + " cellInfo=" + cellInfo);
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCellInfo.set(phoneId, cellInfo);
@@ -1450,7 +1448,7 @@
             log("notifyCallForwardingChangedForSubscriber: subId=" + subId
                 + " cfi=" + cfi);
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCallForwarding[phoneId] = cfi;
@@ -1478,7 +1476,7 @@
         if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mDataActivity[phoneId] = state;
@@ -1613,7 +1611,7 @@
             log("notifyCellLocationForSubscriber: subId=" + subId
                 + " cellLocation=" + cellLocation);
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mCellLocation[phoneId] = cellLocation;
@@ -1641,7 +1639,7 @@
         if (!checkNotifyPermission("notifyOtaspChanged()" )) {
             return;
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mOtaspMode[phoneId] = otaspMode;
@@ -1745,7 +1743,7 @@
         if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) {
             return;
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mImsReasonInfo.set(phoneId, imsReasonInfo);
@@ -1805,7 +1803,7 @@
         if (VDBG) {
             log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state);
         }
-        int phoneId = getPhoneIdFromSubId(subId);
+        int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mSrvccState[phoneId] = state;
@@ -2213,7 +2211,7 @@
             intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
         }
         // If the phoneId is invalid, the broadcast is for overall call state.
-        if (phoneId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+        if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
             intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
             intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
         }
@@ -2686,18 +2684,4 @@
     private static CallQuality createCallQuality() {
         return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
     }
-
-    private int getPhoneIdFromSubId(int subId) {
-        SubscriptionManager subManager = (SubscriptionManager)
-                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        if (subManager == null) return INVALID_SIM_SLOT_INDEX;
-
-        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
-            subId = SubscriptionManager.getDefaultSubscriptionId();
-        }
-
-        SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId);
-        if (info == null) return INVALID_SIM_SLOT_INDEX;
-        return info.getSimSlotIndex();
-    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c2dd046..b55d6ad 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -490,7 +490,7 @@
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     // How many bytes to write into the dropbox log before truncating
-    static final int DROPBOX_MAX_SIZE = 192 * 1024;
+    static final int DROPBOX_DEFAULT_MAX_SIZE = 192 * 1024;
     // Assumes logcat entries average around 100 bytes; that's not perfect stack traces count
     // as one line, but close enough for now.
     static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
@@ -9770,9 +9770,12 @@
                     sb.append(report);
                 }
 
-                String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
-                int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);
-                int maxDataFileSize = DROPBOX_MAX_SIZE - sb.length()
+                String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
+                String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag;
+                int lines = Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0);
+                int dropboxMaxSize = Settings.Global.getInt(
+                        mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE);
+                int maxDataFileSize = dropboxMaxSize - sb.length()
                         - lines * RESERVED_BYTES_PER_LOGCAT_LINE;
 
                 if (dataFile != null && maxDataFileSize > 0) {
@@ -18433,7 +18436,7 @@
         public ActivityPresentationInfo getActivityPresentationInfo(IBinder token) {
             int displayId = Display.INVALID_DISPLAY;
             try {
-                displayId = mActivityTaskManager.getActivityDisplayId(token);
+                displayId = mActivityTaskManager.getDisplayId(token);
             } catch (RemoteException e) {
             }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1a62eb2..335cac8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4488,12 +4488,13 @@
         }
 
         if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
+                && !isStreamMutedByRingerOrZenMode(AudioSystem.STREAM_MUSIC)
                 && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
                 && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
                 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
                 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
             if (DEBUG_VOL) {
-                Log.i(TAG, String.format(" onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
+                Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
                         newDevice, AudioSystem.getOutputDeviceName(newDevice)));
             }
             mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
@@ -6167,6 +6168,7 @@
         pw.println("\nRinger mode: ");
         pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
         pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
+        pw.println("- zen mode:" + Settings.Global.zenModeToString(mNm.getZenMode()));
         dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
         dumpRingerModeStreams(pw, "muted", mRingerAndZenModeMutedStreams);
         pw.print("- delegate = "); pw.println(mRingerModeDelegate);
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
index a91fe77..1cf27ff 100644
--- a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -231,7 +231,8 @@
                 // a Sim with a different mcc code was found
                 neededNow = false;
             }
-            String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
+            String simOperator = mTelephonyManager
+                    .createForSubscriptionId(info.getSubscriptionId()).getSimOperator();
             mcc = 0;
             if (simOperator != null && simOperator.length() >= 3) {
                 mcc = Integer.parseInt(simOperator.substring(0, 3));
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
new file mode 100644
index 0000000..1b1a292
--- /dev/null
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.incremental;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.DataLoaderManager;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.incremental.IIncrementalManager;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+
+/**
+ * This service has the following purposes:
+ * 1) Starts the IIncrementalManager binder service.
+ * 1) Starts the native IIncrementalManagerService binder service.
+ * 2) Handles shell commands for "incremental" service.
+ * 3) Handles binder calls from the native IIncrementalManagerService binder service and pass
+ *    them to a data loader binder service.
+ */
+
+public class IncrementalManagerService extends IIncrementalManager.Stub  {
+    private static final String TAG = "IncrementalManagerService";
+    private static final String BINDER_SERVICE_NAME = "incremental";
+    // DataLoaderManagerService should have been started before us
+    private @NonNull DataLoaderManager mDataLoaderManager;
+    private long mNativeInstance;
+    private final @NonNull Context mContext;
+
+    /**
+     * Starts IIncrementalManager binder service and register to Service Manager.
+     * Starts the native IIncrementalManagerNative binder service.
+     */
+    public static IncrementalManagerService start(Context context) {
+        IncrementalManagerService self = new IncrementalManagerService(context);
+        if (self.mNativeInstance == 0) {
+            return null;
+        }
+        return self;
+    }
+
+    private IncrementalManagerService(Context context) {
+        mContext = context;
+        mDataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+        ServiceManager.addService(BINDER_SERVICE_NAME, this);
+        // Starts and register IIncrementalManagerNative service
+        // TODO(b/136132412): add jni implementation
+    }
+    /**
+     * Notifies native IIncrementalManager service that system is ready.
+     */
+    public void systemReady() {
+        // TODO(b/136132412): add jni implementation
+    }
+
+    /**
+     * Finds data loader service provider and binds to it. This requires PackageManager.
+     */
+    @Override
+    public boolean prepareDataLoader(int mountId, IncrementalFileSystemControlParcel control,
+            IncrementalDataLoaderParamsParcel params,
+            IDataLoaderStatusListener listener) {
+        Bundle dataLoaderParams = new Bundle();
+        dataLoaderParams.putCharSequence("packageName", params.packageName);
+        dataLoaderParams.putParcelable("control", control);
+        dataLoaderParams.putParcelable("params", params);
+        DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
+        if (dataLoaderManager == null) {
+            Slog.e(TAG, "Failed to find data loader manager service");
+            return false;
+        }
+        if (!dataLoaderManager.initializeDataLoader(mountId, dataLoaderParams, listener)) {
+            Slog.e(TAG, "Failed to initialize data loader");
+            return false;
+        }
+        return true;
+    }
+
+
+    @Override
+    public boolean startDataLoader(int mountId) {
+        IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+        if (dataLoader == null) {
+            Slog.e(TAG, "Start failed to retrieve data loader for ID=" + mountId);
+            return false;
+        }
+        try {
+            // TODO: fix file list
+            dataLoader.start(null);
+            return true;
+        } catch (RemoteException ex) {
+            return false;
+        }
+    }
+
+    @Override
+    public void destroyDataLoader(int mountId) {
+        IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+        if (dataLoader == null) {
+            Slog.e(TAG, "Destroy failed to retrieve data loader for ID=" + mountId);
+            return;
+        }
+        try {
+            dataLoader.destroy();
+        } catch (RemoteException ex) {
+            return;
+        }
+    }
+
+    // TODO: remove this
+    @Override
+    public void newFileForDataLoader(int mountId, long inode, byte[] metadata) {
+        IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
+        if (dataLoader == null) {
+            Slog.e(TAG, "Failed to retrieve data loader for ID=" + mountId);
+            return;
+        }
+        try {
+            dataLoader.onFileCreated(inode, metadata);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    @Override
+    public void showHealthBlockedUI(int mountId) {
+        // TODO(b/136132412): implement this
+    }
+
+    @Override
+    public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            FileDescriptor err, @NonNull String[] args, ShellCallback callback,
+            @NonNull ResultReceiver resultReceiver) {
+        (new IncrementalManagerShellCommand(mContext)).exec(
+                this, in, out, err, args, callback, resultReceiver);
+    }
+}
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
new file mode 100644
index 0000000..d35e806
--- /dev/null
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.incremental;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.InstallationFile;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.ShellCommand;
+import android.os.incremental.IncrementalDataLoaderParams;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Defines actions to handle adb commands like "adb abb incremental ...".
+ */
+public final class IncrementalManagerShellCommand extends ShellCommand {
+    private static final String TAG = "IncrementalShellCommand";
+    // Assuming the adb data loader is always installed on the device
+    private static final String LOADER_PACKAGE_NAME = "com.android.incremental.nativeadb";
+    private final @NonNull Context mContext;
+
+    private static final int ERROR_INVALID_ARGUMENTS = -1;
+    private static final int ERROR_DATA_LOADER_INIT = -2;
+    private static final int ERROR_COMMAND_EXECUTION = -3;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ERROR_INVALID_ARGUMENTS, ERROR_DATA_LOADER_INIT, ERROR_COMMAND_EXECUTION})
+    public @interface IncrementalShellCommandErrorCode {
+    }
+
+    IncrementalManagerShellCommand(@NonNull Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public int onCommand(@Nullable String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(null);
+        }
+        switch (cmd) {
+            case "install-start":
+                return runInstallStart();
+            case "install-finish":
+                return runInstallFinish();
+            default:
+                return handleDefaultCommands(cmd);
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Incremental Service Commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("  install-start");
+        pw.println("    Opens an installation session");
+        pw.println("  install-finish SESSION_ID --file NAME:SIZE:INDEX --file NAME:SIZE:INDEX ...");
+        pw.println("    Commits an installation session specified by session ID for an APK ");
+        pw.println("      or a bundle of splits. Configures lib dirs or OBB files if specified.");
+    }
+
+    private int runInstallStart() {
+        final PrintWriter pw = getOutPrintWriter();
+        final PackageInstaller packageInstaller =
+                mContext.getPackageManager().getPackageInstaller();
+        if (packageInstaller == null) {
+            pw.println("Failed to get PackageInstaller.");
+            return ERROR_COMMAND_EXECUTION;
+        }
+
+        final Map<String, ParcelFileDescriptor> dataLoaderDynamicArgs = getDataLoaderDynamicArgs();
+        if (dataLoaderDynamicArgs == null) {
+            pw.println("File names and sizes don't match.");
+            return ERROR_DATA_LOADER_INIT;
+        }
+        final IncrementalDataLoaderParams params = new IncrementalDataLoaderParams(
+                "", LOADER_PACKAGE_NAME, dataLoaderDynamicArgs);
+        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        sessionParams.installFlags |= PackageManager.INSTALL_ALL_USERS;
+        // Replace existing if same package is already installed
+        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+        sessionParams.setIncrementalParams(params);
+
+        try {
+            int sessionId = packageInstaller.createSession(sessionParams);
+            pw.println("Successfully opened session: sessionId = " + sessionId);
+        } catch (Exception ex) {
+            pw.println("Failed to create session.");
+            return ERROR_COMMAND_EXECUTION;
+        } finally {
+            try {
+                for (Map.Entry<String, ParcelFileDescriptor> nfd
+                        : dataLoaderDynamicArgs.entrySet()) {
+                    nfd.getValue().close();
+                }
+            } catch (IOException ignored) {
+            }
+        }
+        return 0;
+    }
+
+    private int runInstallFinish() {
+        final PrintWriter pw = getOutPrintWriter();
+        final int sessionId = parseInt(getNextArgRequired());
+        final List<InstallationFile> installationFiles = parseFileArgs(pw);
+        if (installationFiles == null) {
+            pw.println("Must specify at least one file to install.");
+            return ERROR_INVALID_ARGUMENTS;
+        }
+        final int numFiles = installationFiles.size();
+        if (numFiles == 0) {
+            pw.println("Must specify at least one file to install.");
+            return ERROR_INVALID_ARGUMENTS;
+        }
+
+        final PackageInstaller packageInstaller = mContext.getPackageManager()
+                .getPackageInstaller();
+        if (packageInstaller == null) {
+            pw.println("Failed to get PackageInstaller.");
+            return ERROR_COMMAND_EXECUTION;
+        }
+
+        final LocalIntentReceiver localReceiver = new LocalIntentReceiver();
+        boolean success = false;
+
+        PackageInstaller.Session session = null;
+        try {
+            session = packageInstaller.openSession(sessionId);
+            for (int i = 0; i < numFiles; i++) {
+                InstallationFile file = installationFiles.get(i);
+                session.addFile(file.getName(), file.getSize(), file.getMetadata());
+            }
+            session.commit(localReceiver.getIntentSender());
+            final Intent result = localReceiver.getResult();
+            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                    PackageInstaller.STATUS_FAILURE);
+            if (status == PackageInstaller.STATUS_SUCCESS) {
+                success = true;
+                pw.println("Success");
+                return 0;
+            } else {
+                pw.println("Failure ["
+                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+                return ERROR_COMMAND_EXECUTION;
+            }
+        } catch (Exception e) {
+            e.printStackTrace(pw);
+            return ERROR_COMMAND_EXECUTION;
+        } finally {
+            if (!success) {
+                try {
+                    if (session != null) {
+                        session.abandon();
+                    }
+                } catch (Exception ignore) {
+                }
+            }
+        }
+    }
+
+    private static class LocalIntentReceiver {
+        private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
+
+        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+            @Override
+            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+                    IIntentReceiver finishedReceiver, String requiredPermission,
+                    Bundle options) {
+                try {
+                    mResult.offer(intent, 5, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
+
+        public IntentSender getIntentSender() {
+            return new IntentSender((IIntentSender) mLocalSender);
+        }
+
+        public Intent getResult() {
+            try {
+                return mResult.take();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /** Helpers. */
+    private Map<String, ParcelFileDescriptor> getDataLoaderDynamicArgs() {
+        Map<String, ParcelFileDescriptor> dataLoaderDynamicArgs = new HashMap<>();
+        final FileDescriptor outFd = getOutFileDescriptor();
+        final FileDescriptor inFd = getInFileDescriptor();
+        try {
+            dataLoaderDynamicArgs.put("inFd", ParcelFileDescriptor.dup(inFd));
+            dataLoaderDynamicArgs.put("outFd", ParcelFileDescriptor.dup(outFd));
+            return dataLoaderDynamicArgs;
+        } catch (Exception ex) {
+            Slog.e(TAG, "Failed to dup FDs");
+            return null;
+        }
+    }
+
+    private long parseLong(String arg) {
+        long result = -1;
+        try {
+            result = Long.parseLong(arg);
+        } catch (NumberFormatException e) {
+        }
+        return result;
+    }
+
+    private int parseInt(String arg) {
+        int result = -1;
+        try {
+            result = Integer.parseInt(arg);
+        } catch (NumberFormatException e) {
+        }
+        return result;
+    }
+
+    private List<InstallationFile> parseFileArgs(PrintWriter pw) {
+        List<InstallationFile> fileList = new ArrayList<>();
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--file": {
+                    final String fileArgs = getNextArgRequired();
+                    final String[] args = fileArgs.split(":");
+                    if (args.length != 3) {
+                        pw.println("Invalid file args: " + fileArgs);
+                        return null;
+                    }
+                    final String name = args[0];
+                    final long size = parseLong(args[1]);
+                    if (size < 0) {
+                        pw.println("Invalid file size in: " + fileArgs);
+                        return null;
+                    }
+                    final long index = parseLong(args[2]);
+                    if (index < 0) {
+                        pw.println("Invalid file index in: " + fileArgs);
+                        return null;
+                    }
+                    final byte[] metadata = String.valueOf(index).getBytes(StandardCharsets.UTF_8);
+                    fileList.add(new InstallationFile(name, size, metadata));
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+        return fileList;
+    }
+}
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index 3d18d4a..f625452 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemConfig;
@@ -113,6 +114,16 @@
                 () -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(), handler);
     }
 
+    /** Called when system is ready. */
+    public synchronized void onSystemReady() {
+        mLocationMode.register();
+        mBackgroundThrottleIntervalMs.register();
+        mLocationPackageBlacklist.register();
+        mLocationPackageWhitelist.register();
+        mBackgroundThrottlePackageWhitelist.register();
+        mIgnoreSettingsPackageWhitelist.register();
+    }
+
     /**
      * Retrieve if location is enabled or not.
      */
@@ -300,13 +311,25 @@
     private abstract static class ObservingSetting extends ContentObserver {
 
         private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
+        private boolean mRegistered;
 
-        private ObservingSetting(Context context, String settingName, Handler handler) {
+        private ObservingSetting(Handler handler) {
             super(handler);
             mListeners = new CopyOnWriteArrayList<>();
+        }
+
+        protected boolean isRegistered() {
+            return mRegistered;
+        }
+
+        protected void register(Context context, Uri uri) {
+            if (mRegistered) {
+                return;
+            }
 
             context.getContentResolver().registerContentObserver(
-                    getUriFor(settingName), false, this, UserHandle.USER_ALL);
+                    uri, false, this, UserHandle.USER_ALL);
+            mRegistered = true;
         }
 
         public void addListener(UserSettingChangedListener listener) {
@@ -317,8 +340,6 @@
             mListeners.remove(listener);
         }
 
-        protected abstract Uri getUriFor(String settingName);
-
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             for (UserSettingChangedListener listener : mListeners) {
@@ -333,20 +354,19 @@
         private final String mSettingName;
 
         private IntegerSecureSetting(Context context, String settingName, Handler handler) {
-            super(context, settingName, handler);
+            super(handler);
             mContext = context;
             mSettingName = settingName;
         }
 
+        private void register() {
+            register(mContext, Settings.Secure.getUriFor(mSettingName));
+        }
+
         public int getValueForUser(int defaultValue, int userId) {
             return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
                     defaultValue, userId);
         }
-
-        @Override
-        protected Uri getUriFor(String settingName) {
-            return Settings.Secure.getUriFor(settingName);
-        }
     }
 
     private static class StringListCachedSecureSetting extends ObservingSetting {
@@ -354,31 +374,44 @@
         private final Context mContext;
         private final String mSettingName;
 
-        private int mCachedUserId = UserHandle.USER_NULL;
+        @GuardedBy("this")
+        private int mCachedUserId;
+        @GuardedBy("this")
         private List<String> mCachedValue;
 
         private StringListCachedSecureSetting(Context context, String settingName,
                 Handler handler) {
-            super(context, settingName, handler);
+            super(handler);
             mContext = context;
             mSettingName = settingName;
+
+            mCachedUserId = UserHandle.USER_NULL;
+        }
+
+        public synchronized void register() {
+            register(mContext, Settings.Secure.getUriFor(mSettingName));
         }
 
         public synchronized List<String> getValueForUser(int userId) {
             Preconditions.checkArgument(userId != UserHandle.USER_NULL);
 
+            List<String> value = mCachedValue;
             if (userId != mCachedUserId) {
                 String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                         mSettingName, userId);
                 if (TextUtils.isEmpty(setting)) {
-                    mCachedValue = Collections.emptyList();
+                    value = Collections.emptyList();
                 } else {
-                    mCachedValue = Arrays.asList(setting.split(","));
+                    value = Arrays.asList(setting.split(","));
                 }
-                mCachedUserId = userId;
+
+                if (isRegistered()) {
+                    mCachedUserId = userId;
+                    mCachedValue = value;
+                }
             }
 
-            return mCachedValue;
+            return value;
         }
 
         public synchronized void invalidateForUser(int userId) {
@@ -393,11 +426,6 @@
             invalidateForUser(userId);
             super.onChange(selfChange, uri, userId);
         }
-
-        @Override
-        protected Uri getUriFor(String settingName) {
-            return Settings.Secure.getUriFor(settingName);
-        }
     }
 
     private static class LongGlobalSetting extends ObservingSetting {
@@ -406,20 +434,19 @@
         private final String mSettingName;
 
         private LongGlobalSetting(Context context, String settingName, Handler handler) {
-            super(context, settingName, handler);
+            super(handler);
             mContext = context;
             mSettingName = settingName;
         }
 
+        public void register() {
+            register(mContext, Settings.Global.getUriFor(mSettingName));
+        }
+
         public long getValue(long defaultValue) {
             return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
                     defaultValue);
         }
-
-        @Override
-        protected Uri getUriFor(String settingName) {
-            return Settings.Global.getUriFor(settingName);
-        }
     }
 
     private static class StringSetCachedGlobalSetting extends ObservingSetting {
@@ -428,29 +455,42 @@
         private final String mSettingName;
         private final Supplier<ArraySet<String>> mBaseValuesSupplier;
 
+        @GuardedBy("this")
         private boolean mValid;
+        @GuardedBy("this")
         private ArraySet<String> mCachedValue;
 
         private StringSetCachedGlobalSetting(Context context, String settingName,
                 Supplier<ArraySet<String>> baseValuesSupplier, Handler handler) {
-            super(context, settingName, handler);
+            super(handler);
             mContext = context;
             mSettingName = settingName;
             mBaseValuesSupplier = baseValuesSupplier;
+
+            mValid = false;
+        }
+
+        public synchronized void register() {
+            register(mContext, Settings.Global.getUriFor(mSettingName));
         }
 
         public synchronized Set<String> getValue() {
+            ArraySet<String> value = mCachedValue;
             if (!mValid) {
-                mCachedValue = new ArraySet<>(mBaseValuesSupplier.get());
+                value = new ArraySet<>(mBaseValuesSupplier.get());
                 String setting = Settings.Global.getString(mContext.getContentResolver(),
                         mSettingName);
                 if (!TextUtils.isEmpty(setting)) {
-                    mCachedValue.addAll(Arrays.asList(setting.split(",")));
+                    value.addAll(Arrays.asList(setting.split(",")));
                 }
-                mValid = true;
+
+                if (isRegistered()) {
+                    mValid = true;
+                    mCachedValue = value;
+                }
             }
 
-            return mCachedValue;
+            return value;
         }
 
         public synchronized void invalidate() {
@@ -463,10 +503,5 @@
             invalidate();
             super.onChange(selfChange, uri, userId);
         }
-
-        @Override
-        protected Uri getUriFor(String settingName) {
-            return Settings.Global.getUriFor(settingName);
-        }
     }
 }
diff --git a/services/core/java/com/android/server/LocationUsageLogger.java b/services/core/java/com/android/server/location/LocationUsageLogger.java
similarity index 72%
rename from services/core/java/com/android/server/LocationUsageLogger.java
rename to services/core/java/com/android/server/location/LocationUsageLogger.java
index a8a3cc4..755438b 100644
--- a/services/core/java/com/android/server/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/LocationUsageLogger.java
@@ -14,37 +14,113 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.location;
+
+import static com.android.server.LocationManagerService.TAG;
 
 import android.app.ActivityManager;
 import android.location.Geofence;
 import android.location.LocationManager;
 import android.location.LocationRequest;
-import android.os.SystemClock;
 import android.stats.location.LocationStatsEnums;
 import android.util.Log;
 import android.util.StatsLog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.time.Instant;
 
 /**
  * Logger for Location API usage logging.
  */
 public class LocationUsageLogger {
-    private static final String TAG = "LocationUsageLogger";
-    private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int ONE_SEC_IN_MILLIS = 1000;
     private static final int ONE_MINUTE_IN_MILLIS = 60000;
     private static final int ONE_HOUR_IN_MILLIS = 3600000;
 
-    private long mLastApiUsageLogHour = 0;
-
-    private int mApiUsageLogHourlyCount = 0;
-
     private static final int API_USAGE_LOG_HOURLY_CAP = 60;
 
-    private static int providerNameToStatsdEnum(String provider) {
+    @GuardedBy("this")
+    private long mLastApiUsageLogHour = 0;
+    @GuardedBy("this")
+    private int mApiUsageLogHourlyCount = 0;
+
+    /**
+     * Log a location API usage event.
+     */
+    public void logLocationApiUsage(int usageType, int apiInUse,
+            String packageName, LocationRequest locationRequest,
+            boolean hasListener, boolean hasIntent,
+            Geofence geofence, int activityImportance) {
+        try {
+            if (hitApiUsageLogCap()) {
+                return;
+            }
+
+            boolean isLocationRequestNull = locationRequest == null;
+            boolean isGeofenceNull = geofence == null;
+
+            StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
+                    apiInUse, packageName,
+                    isLocationRequestNull
+                        ? LocationStatsEnums.PROVIDER_UNKNOWN
+                        : bucketizeProvider(locationRequest.getProvider()),
+                    isLocationRequestNull
+                        ? LocationStatsEnums.QUALITY_UNKNOWN
+                        : locationRequest.getQuality(),
+                    isLocationRequestNull
+                        ? LocationStatsEnums.INTERVAL_UNKNOWN
+                        : bucketizeInterval(locationRequest.getInterval()),
+                    isLocationRequestNull
+                        ? LocationStatsEnums.DISTANCE_UNKNOWN
+                        : bucketizeDistance(
+                                locationRequest.getSmallestDisplacement()),
+                    isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
+                    // only log expireIn for USAGE_STARTED
+                    isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
+                        ? LocationStatsEnums.EXPIRATION_UNKNOWN
+                        : bucketizeExpireIn(locationRequest.getExpireIn()),
+                    getCallbackType(apiInUse, hasListener, hasIntent),
+                    isGeofenceNull
+                        ? LocationStatsEnums.RADIUS_UNKNOWN
+                        : bucketizeRadius(geofence.getRadius()),
+                    categorizeActivityImportance(activityImportance));
+        } catch (Exception e) {
+            // Swallow exceptions to avoid crashing LMS.
+            Log.w(TAG, "Failed to log API usage to statsd.", e);
+        }
+    }
+
+    /**
+     * Log a location API usage event.
+     */
+    public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
+        try {
+            if (hitApiUsageLogCap()) {
+                return;
+            }
+
+            StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
+                    /* package_name= */ null,
+                    bucketizeProvider(providerName),
+                    LocationStatsEnums.QUALITY_UNKNOWN,
+                    LocationStatsEnums.INTERVAL_UNKNOWN,
+                    LocationStatsEnums.DISTANCE_UNKNOWN,
+                    /* numUpdates= */ 0,
+                    LocationStatsEnums.EXPIRATION_UNKNOWN,
+                    getCallbackType(
+                            apiInUse,
+                            /* isListenerNull= */ true,
+                            /* isIntentNull= */ true),
+                    /* bucketizedRadius= */ 0,
+                    LocationStatsEnums.IMPORTANCE_UNKNOWN);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to log API usage to statsd.", e);
+        }
+    }
+
+    private static int bucketizeProvider(String provider) {
         if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
             return LocationStatsEnums.PROVIDER_NETWORK;
         } else if (LocationManager.GPS_PROVIDER.equals(provider)) {
@@ -58,8 +134,7 @@
         }
     }
 
-    private static int bucketizeIntervalToStatsdEnum(long interval) {
-        // LocationManager already converts negative values to 0.
+    private static int bucketizeInterval(long interval) {
         if (interval < ONE_SEC_IN_MILLIS) {
             return LocationStatsEnums.INTERVAL_BETWEEN_0_SEC_AND_1_SEC;
         } else if (interval < ONE_SEC_IN_MILLIS * 5) {
@@ -75,9 +150,8 @@
         }
     }
 
-    private static int bucketizeSmallestDisplacementToStatsdEnum(float smallestDisplacement) {
-        // LocationManager already converts negative values to 0.
-        if (smallestDisplacement == 0) {
+    private static int bucketizeDistance(float smallestDisplacement) {
+        if (smallestDisplacement <= 0) {
             return LocationStatsEnums.DISTANCE_ZERO;
         } else if (smallestDisplacement > 0 && smallestDisplacement <= 100) {
             return LocationStatsEnums.DISTANCE_BETWEEN_0_AND_100;
@@ -86,7 +160,7 @@
         }
     }
 
-    private static int bucketizeRadiusToStatsdEnum(float radius) {
+    private static int bucketizeRadius(float radius) {
         if (radius < 0) {
             return LocationStatsEnums.RADIUS_NEGATIVE;
         } else if (radius < 100) {
@@ -104,14 +178,11 @@
         }
     }
 
-    private static int getBucketizedExpireIn(long expireAt) {
-        if (expireAt == Long.MAX_VALUE) {
+    private static int bucketizeExpireIn(long expireIn) {
+        if (expireIn == Long.MAX_VALUE) {
             return LocationStatsEnums.EXPIRATION_NO_EXPIRY;
         }
 
-        long elapsedRealtime = SystemClock.elapsedRealtime();
-        long expireIn = Math.max(0, expireAt - elapsedRealtime);
-
         if (expireIn < 20 * ONE_SEC_IN_MILLIS) {
             return LocationStatsEnums.EXPIRATION_BETWEEN_0_AND_20_SEC;
         } else if (expireIn < ONE_MINUTE_IN_MILLIS) {
@@ -129,8 +200,8 @@
         if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
             return LocationStatsEnums.IMPORTANCE_TOP;
         } else if (importance == ActivityManager
-                                    .RunningAppProcessInfo
-                                    .IMPORTANCE_FOREGROUND_SERVICE) {
+                .RunningAppProcessInfo
+                .IMPORTANCE_FOREGROUND_SERVICE) {
             return LocationStatsEnums.IMPORTANCE_FORGROUND_SERVICE;
         } else {
             return LocationStatsEnums.IMPORTANCE_BACKGROUND;
@@ -154,117 +225,16 @@
         }
     }
 
-    // Update the hourly count of APIUsage log event.
-    // Returns false if hit the hourly log cap.
-    private boolean checkApiUsageLogCap() {
-        if (D) {
-            Log.d(TAG, "checking APIUsage log cap.");
-        }
-
+    private synchronized boolean hitApiUsageLogCap() {
         long currentHour = Instant.now().toEpochMilli() / ONE_HOUR_IN_MILLIS;
         if (currentHour > mLastApiUsageLogHour) {
             mLastApiUsageLogHour = currentHour;
             mApiUsageLogHourlyCount = 0;
-            return true;
+            return false;
         } else {
             mApiUsageLogHourlyCount = Math.min(
-                mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
-            return mApiUsageLogHourlyCount < API_USAGE_LOG_HOURLY_CAP;
-        }
-    }
-
-    /**
-     * Log a Location API usage event to Statsd.
-     * Logging event is capped at 60 per hour. Usage events exceeding
-     * the cap will be dropped by LocationUsageLogger.
-     */
-    public void logLocationApiUsage(int usageType, int apiInUse,
-            String packageName, LocationRequest locationRequest,
-            boolean hasListener, boolean hasIntent,
-            Geofence geofence, int activityImportance) {
-        try {
-            if (!checkApiUsageLogCap()) {
-                return;
-            }
-
-            boolean isLocationRequestNull = locationRequest == null;
-            boolean isGeofenceNull = geofence == null;
-            if (D) {
-                Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
-                        + apiInUse + ", packageName: " + (packageName == null ? "" : packageName)
-                        + ", locationRequest: "
-                        + (isLocationRequestNull ? "" : locationRequest.toString())
-                        + ", hasListener: " + hasListener
-                        + ", hasIntent: " + hasIntent
-                        + ", geofence: "
-                        + (isGeofenceNull ? "" : geofence.toString())
-                        + ", importance: " + activityImportance);
-            }
-
-            StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType,
-                    apiInUse, packageName,
-                    isLocationRequestNull
-                        ? LocationStatsEnums.PROVIDER_UNKNOWN
-                        : providerNameToStatsdEnum(locationRequest.getProvider()),
-                    isLocationRequestNull
-                        ? LocationStatsEnums.QUALITY_UNKNOWN
-                        : locationRequest.getQuality(),
-                    isLocationRequestNull
-                        ? LocationStatsEnums.INTERVAL_UNKNOWN
-                        : bucketizeIntervalToStatsdEnum(locationRequest.getInterval()),
-                    isLocationRequestNull
-                        ? LocationStatsEnums.DISTANCE_UNKNOWN
-                        : bucketizeSmallestDisplacementToStatsdEnum(
-                                locationRequest.getSmallestDisplacement()),
-                    isLocationRequestNull ? 0 : locationRequest.getNumUpdates(),
-                    // only log expireIn for USAGE_STARTED
-                    isLocationRequestNull || usageType == LocationStatsEnums.USAGE_ENDED
-                        ? LocationStatsEnums.EXPIRATION_UNKNOWN
-                        : getBucketizedExpireIn(locationRequest.getExpireAt()),
-                    getCallbackType(apiInUse, hasListener, hasIntent),
-                    isGeofenceNull
-                        ? LocationStatsEnums.RADIUS_UNKNOWN
-                        : bucketizeRadiusToStatsdEnum(geofence.getRadius()),
-                    categorizeActivityImportance(activityImportance));
-        } catch (Exception e) {
-            // Swallow exceptions to avoid crashing LMS.
-            Log.w(TAG, "Failed to log API usage to statsd.", e);
-        }
-    }
-
-    /**
-     * Log a Location API usage event to Statsd.
-     * Logging event is capped at 60 per hour. Usage events exceeding
-     * the cap will be dropped by LocationUsageLogger.
-     */
-    public void logLocationApiUsage(int usageType, int apiInUse, String providerName) {
-        try {
-            if (!checkApiUsageLogCap()) {
-                return;
-            }
-
-            if (D) {
-                Log.d(TAG, "log API Usage to statsd. usageType: " + usageType + ", apiInUse: "
-                        + apiInUse + ", providerName: " + providerName);
-            }
-
-            StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse,
-                    /* package_name= */ null,
-                    providerNameToStatsdEnum(providerName),
-                    LocationStatsEnums.QUALITY_UNKNOWN,
-                    LocationStatsEnums.INTERVAL_UNKNOWN,
-                    LocationStatsEnums.DISTANCE_UNKNOWN,
-                    /* numUpdates= */ 0,
-                    LocationStatsEnums.EXPIRATION_UNKNOWN,
-                    getCallbackType(
-                            apiInUse,
-                            /* isListenerNull= */ true,
-                            /* isIntentNull= */ true),
-                    /* bucketizedRadius= */ 0,
-                    LocationStatsEnums.IMPORTANCE_UNKNOWN);
-        } catch (Exception e) {
-            // Swallow exceptions to avoid crashing LMS.
-            Log.w(TAG, "Failed to log API usage to statsd.", e);
+                    mApiUsageLogHourlyCount + 1, API_USAGE_LOG_HOURLY_CAP);
+            return mApiUsageLogHourlyCount >= API_USAGE_LOG_HOURLY_CAP;
         }
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c25e206..2cb7e3b 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -70,6 +70,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -1042,6 +1043,13 @@
         private boolean mVoiceButtonHandled = false;
 
         @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            (new MediaShellCommand()).exec(this, in, out, err, args, callback,
+                    resultReceiver);
+        }
+
+        @Override
         public ISession createSession(String packageName, ISessionCallback cb, String tag,
                 Bundle sessionInfo, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/services/core/java/com/android/server/media/MediaShellCommand.java
similarity index 64%
rename from cmds/media/src/com/android/commands/media/Media.java
rename to services/core/java/com/android/server/media/MediaShellCommand.java
index 1e915f8..20df271 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -1,29 +1,27 @@
 /*
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright (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.commands.media;
+package com.android.server.media;
 
 import android.app.ActivityThread;
 import android.content.Context;
 import android.media.MediaMetadata;
 import android.media.session.ISessionManager;
 import android.media.session.MediaController;
-import android.media.session.MediaController.PlaybackInfo;
-import android.media.session.MediaSession.QueueItem;
+import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
@@ -31,59 +29,41 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ShellCommand;
 import android.os.SystemClock;
-import android.util.AndroidException;
+import android.text.TextUtils;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
-import com.android.internal.os.BaseCommand;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.util.List;
 
-public class Media extends BaseCommand {
+/**
+ * ShellCommand for MediaSessionService.
+ */
+public class MediaShellCommand extends ShellCommand {
     // This doesn't belongs to any package. Setting the package name to empty string.
     private static final String PACKAGE_NAME = "";
     private static ActivityThread sThread;
     private static MediaSessionManager sMediaSessionManager;
     private ISessionManager mSessionService;
-
-    /**
-     * Command-line entry point.
-     *
-     * @param args The command-line arguments
-     */
-    public static void main(String[] args) {
-        (new Media()).run(args);
-    }
+    private PrintWriter mWriter;
+    private PrintWriter mErrorWriter;
 
     @Override
-    public void onShowUsage(PrintStream out) {
-        out.println(
-                "usage: media [subcommand] [options]\n" +
-                "       media dispatch KEY\n" +
-                "       media list-sessions\n" +
-                "       media monitor <tag>\n" +
-                "       media volume [options]\n" +
-                "\n" +
-                "media dispatch: dispatch a media key to the system.\n" +
-                "                KEY may be: play, pause, play-pause, mute, headsethook,\n" +
-                "                stop, next, previous, rewind, record, fast-forword.\n" +
-                "media list-sessions: print a list of the current sessions.\n" +
-                        "media monitor: monitor updates to the specified session.\n" +
-                "                       Use the tag from list-sessions.\n" +
-                "media volume:  " + VolumeCtrl.USAGE
-        );
-    }
+    public int onCommand(String cmd) {
+        mWriter = getOutPrintWriter();
+        mErrorWriter = getErrPrintWriter();
 
-    @Override
-    public void onRun() throws Exception {
+        if (TextUtils.isEmpty(cmd)) {
+            return handleDefaultCommands(cmd);
+        }
         if (sThread == null) {
-            Looper.prepareMainLooper();
+            Looper.prepare();
             sThread = ActivityThread.systemMain();
             Context context = sThread.getSystemContext();
             sMediaSessionManager =
@@ -92,25 +72,47 @@
         mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
                 Context.MEDIA_SESSION_SERVICE));
         if (mSessionService == null) {
-            System.err.println(NO_SYSTEM_ERROR_CODE);
-            throw new AndroidException(
+            throw new IllegalStateException(
                     "Can't connect to media session service; is the system running?");
         }
 
-        String op = nextArgRequired();
-
-        if (op.equals("dispatch")) {
-            runDispatch();
-        } else if (op.equals("list-sessions")) {
-            runListSessions();
-        } else if (op.equals("monitor")) {
-            runMonitor();
-        } else if (op.equals("volume")) {
-            runVolume();
-        } else {
-            showError("Error: unknown command '" + op + "'");
-            return;
+        try {
+            if (cmd.equals("dispatch")) {
+                runDispatch();
+            } else if (cmd.equals("list-sessions")) {
+                runListSessions();
+            } else if (cmd.equals("monitor")) {
+                runMonitor();
+            } else if (cmd.equals("volume")) {
+                runVolume();
+            } else {
+                showError("Error: unknown command '" + cmd + "'");
+                return -1;
+            }
+        } catch (Exception e) {
+            showError(e.toString());
+            return -1;
         }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        mWriter.println("usage: media_session [subcommand] [options]");
+        mWriter.println("       media_session dispatch KEY");
+        mWriter.println("       media_session dispatch KEY");
+        mWriter.println("       media_session list-sessions");
+        mWriter.println("       media_session monitor <tag>");
+        mWriter.println("       media_session volume [options]");
+        mWriter.println();
+        mWriter.println("media_session dispatch: dispatch a media key to the system.");
+        mWriter.println("                KEY may be: play, pause, play-pause, mute, headsethook,");
+        mWriter.println("                stop, next, previous, rewind, record, fast-forword.");
+        mWriter.println("media_session list-sessions: print a list of the current sessions.");
+        mWriter.println("media_session monitor: monitor updates to the specified session.");
+        mWriter.println("                       Use the tag from list-sessions.");
+        mWriter.println("media_session volume:  " + VolumeCtrl.USAGE);
+        mWriter.println();
     }
 
     private void sendMediaKey(KeyEvent event) {
@@ -121,7 +123,7 @@
     }
 
     private void runMonitor() throws Exception {
-        String id = nextArgRequired();
+        String id = getNextArgRequired();
         if (id == null) {
             showError("Error: must include a session id");
             return;
@@ -133,7 +135,8 @@
             for (MediaController controller : controllers) {
                 try {
                     if (controller != null && id.equals(controller.getTag())) {
-                        ControllerMonitor monitor = new ControllerMonitor(controller);
+                        MediaShellCommand.ControllerMonitor monitor =
+                                new MediaShellCommand.ControllerMonitor(controller);
                         monitor.run();
                         success = true;
                         break;
@@ -143,15 +146,15 @@
                 }
             }
         } catch (Exception e) {
-            System.out.println("***Error monitoring session*** " + e.getMessage());
+            mErrorWriter.println("***Error monitoring session*** " + e.getMessage());
         }
         if (!success) {
-            System.out.println("No session found with id " + id);
+            mErrorWriter.println("No session found with id " + id);
         }
     }
 
     private void runDispatch() throws Exception {
-        String cmd = nextArgRequired();
+        String cmd = getNextArgRequired();
         int keycode;
         if ("play".equals(cmd)) {
             keycode = KeyEvent.KEYCODE_MEDIA_PLAY;
@@ -186,68 +189,73 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
+    void showError(String errMsg) {
+        onHelp();
+        mErrorWriter.println(errMsg);
+    }
+
     class ControllerCallback extends MediaController.Callback {
         @Override
         public void onSessionDestroyed() {
-            System.out.println("onSessionDestroyed. Enter q to quit.");
+            mWriter.println("onSessionDestroyed. Enter q to quit.");
         }
 
         @Override
         public void onSessionEvent(String event, Bundle extras) {
-            System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
+            mWriter.println("onSessionEvent event=" + event + ", extras=" + extras);
         }
 
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
-            System.out.println("onPlaybackStateChanged " + state);
+            mWriter.println("onPlaybackStateChanged " + state);
         }
 
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
             String mmString = metadata == null ? null : "title=" + metadata
                     .getDescription();
-            System.out.println("onMetadataChanged " + mmString);
+            mWriter.println("onMetadataChanged " + mmString);
         }
 
         @Override
-        public void onQueueChanged(List<QueueItem> queue) {
-            System.out.println("onQueueChanged, "
+        public void onQueueChanged(List<MediaSession.QueueItem> queue) {
+            mWriter.println("onQueueChanged, "
                     + (queue == null ? "null queue" : " size=" + queue.size()));
         }
 
         @Override
         public void onQueueTitleChanged(CharSequence title) {
-            System.out.println("onQueueTitleChange " + title);
+            mWriter.println("onQueueTitleChange " + title);
         }
 
         @Override
         public void onExtrasChanged(Bundle extras) {
-            System.out.println("onExtrasChanged " + extras);
+            mWriter.println("onExtrasChanged " + extras);
         }
 
         @Override
-        public void onAudioInfoChanged(PlaybackInfo info) {
-            System.out.println("onAudioInfoChanged " + info);
+        public void onAudioInfoChanged(MediaController.PlaybackInfo info) {
+            mWriter.println("onAudioInfoChanged " + info);
         }
     }
 
     private class ControllerMonitor {
         private final MediaController mController;
-        private final ControllerCallback mControllerCallback;
+        private final MediaShellCommand.ControllerCallback mControllerCallback;
 
         ControllerMonitor(MediaController controller) {
             mController = controller;
-            mControllerCallback = new ControllerCallback();
+            mControllerCallback = new MediaShellCommand.ControllerCallback();
         }
 
         void printUsageMessage() {
             try {
-                System.out.println("V2Monitoring session " + mController.getTag()
+                mWriter.println("V2Monitoring session " + mController.getTag()
                         + "...  available commands: play, pause, next, previous");
             } catch (RuntimeException e) {
-                System.out.println("Error trying to monitor session!");
+                mWriter.println("Error trying to monitor session!");
             }
-            System.out.println("(q)uit: finish monitoring");
+            mWriter.println("(q)uit: finish monitoring");
         }
 
         void run() throws RemoteException {
@@ -258,7 +266,7 @@
                     try {
                         mController.registerCallback(mControllerCallback);
                     } catch (RuntimeException e) {
-                        System.out.println("Error registering monitor callback");
+                        mErrorWriter.println("Error registering monitor callback");
                     }
                 }
             };
@@ -284,7 +292,7 @@
                     } else if ("previous".equals(line)) {
                         dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
                     } else {
-                        System.out.println("Invalid command: " + line);
+                        mErrorWriter.println("Invalid command: " + line);
                     }
 
                     synchronized (this) {
@@ -316,19 +324,19 @@
                 mController.dispatchMediaButtonEvent(down);
                 mController.dispatchMediaButtonEvent(up);
             } catch (RuntimeException e) {
-                System.out.println("Failed to dispatch " + keyCode);
+                mErrorWriter.println("Failed to dispatch " + keyCode);
             }
         }
     }
 
     private void runListSessions() {
-        System.out.println("Sessions:");
+        mWriter.println("Sessions:");
         try {
             List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
             for (MediaController controller : controllers) {
                 if (controller != null) {
                     try {
-                        System.out.println("  tag=" + controller.getTag()
+                        mWriter.println("  tag=" + controller.getTag()
                                 + ", package=" + controller.getPackageName());
                     } catch (RuntimeException e) {
                         // ignore
@@ -336,7 +344,7 @@
                 }
             }
         } catch (Exception e) {
-            System.out.println("***Error listing sessions***");
+            mErrorWriter.println("***Error listing sessions***");
         }
     }
 
diff --git a/cmds/media/src/com/android/commands/media/VolumeCtrl.java b/services/core/java/com/android/server/media/VolumeCtrl.java
old mode 100755
new mode 100644
similarity index 64%
rename from cmds/media/src/com/android/commands/media/VolumeCtrl.java
rename to services/core/java/com/android/server/media/VolumeCtrl.java
index 1629c6f..7a26665
--- a/cmds/media/src/com/android/commands/media/VolumeCtrl.java
+++ b/services/core/java/com/android/server/media/VolumeCtrl.java
@@ -1,21 +1,20 @@
 /*
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * 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.commands.media;
+package com.android.server.media;
 
 import android.content.Context;
 import android.media.AudioManager;
@@ -26,45 +25,41 @@
 
 import com.android.internal.os.BaseCommand;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.lang.ArrayIndexOutOfBoundsException;
-
 /**
  * Command line tool to exercise AudioService.setStreamVolume()
  *                           and AudioService.adjustStreamVolume()
  */
 public class VolumeCtrl {
 
-    private final static String TAG = "VolumeCtrl";
+    private static final String TAG = "VolumeCtrl";
 
     // --stream affects --set, --adj or --get options.
     // --show affects --set and --adj options.
     // --get can be used with --set, --adj or by itself.
-    public final static String USAGE = new String(
-            "the options are as follows: \n" +
-            "\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n" +
-            "\t\t                controls AudioManager.STREAM_MUSIC if no stream is specified\n"+
-            "\t\t--set INDEX     sets the volume index value\n" +
-            "\t\t--adj DIRECTION adjusts the volume, use raise|same|lower for the direction\n" +
-            "\t\t--get           outputs the current volume\n" +
-            "\t\t--show          shows the UI during the volume change\n" +
-            "\texamples:\n" +
-            "\t\tadb shell media volume --show --stream 3 --set 11\n" +
-            "\t\tadb shell media volume --stream 0 --adj lower\n" +
-            "\t\tadb shell media volume --stream 3 --get\n"
-            );
+    public static final String USAGE = new String("the options are as follows: \n"
+            + "\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n"
+            + "\t\t                controls AudioManager.STREAM_MUSIC if no stream is specified\n"
+            + "\t\t--set INDEX     sets the volume index value\n"
+            + "\t\t--adj DIRECTION adjusts the volume, use raise|same|lower for the direction\n"
+            + "\t\t--get           outputs the current volume\n"
+            + "\t\t--show          shows the UI during the volume change\n"
+            + "\texamples:\n"
+            + "\t\tadb shell media volume --show --stream 3 --set 11\n"
+            + "\t\tadb shell media volume --stream 0 --adj lower\n"
+            + "\t\tadb shell media volume --stream 3 --get\n"
+    );
 
-    private final static int VOLUME_CONTROL_MODE_SET = 1;
-    private final static int VOLUME_CONTROL_MODE_ADJUST = 2;
+    private static final int VOLUME_CONTROL_MODE_SET = 1;
+    private static final int VOLUME_CONTROL_MODE_ADJUST = 2;
 
-    private final static String ADJUST_LOWER = "lower";
-    private final static String ADJUST_SAME = "same";
-    private final static String ADJUST_RAISE = "raise";
+    private static final String ADJUST_LOWER = "lower";
+    private static final String ADJUST_SAME = "same";
+    private static final String ADJUST_RAISE = "raise";
 
-    public static void run(BaseCommand cmd) throws Exception {
+    /**
+     * Runs a given MediaShellCommand
+     */
+    public static void run(MediaShellCommand cmd) throws Exception {
         //----------------------------------------
         // Default parameters
         int stream = AudioManager.STREAM_MUSIC;
@@ -78,7 +73,7 @@
         // read options
         String option;
         String adjustment = null;
-        while ((option = cmd.nextOption()) != null) {
+        while ((option = cmd.getNextOption()) != null) {
             switch (option) {
                 case "--show":
                     showUi = true;
@@ -88,17 +83,17 @@
                     log(LOG_V, "will get volume");
                     break;
                 case "--stream":
-                    stream = Integer.decode(cmd.nextArgRequired()).intValue();
+                    stream = Integer.decode(cmd.getNextArgRequired()).intValue();
                     log(LOG_V, "will control stream=" + stream + " (" + streamName(stream) + ")");
                     break;
                 case "--set":
-                    volIndex = Integer.decode(cmd.nextArgRequired()).intValue();
+                    volIndex = Integer.decode(cmd.getNextArgRequired()).intValue();
                     mode = VOLUME_CONTROL_MODE_SET;
                     log(LOG_V, "will set volume to index=" + volIndex);
                     break;
                 case "--adj":
                     mode = VOLUME_CONTROL_MODE_ADJUST;
-                    adjustment = cmd.nextArgRequired();
+                    adjustment = cmd.getNextArgRequired();
                     log(LOG_V, "will adjust volume");
                     break;
                 default:
@@ -140,7 +135,7 @@
             if ((volIndex > audioService.getStreamMaxVolume(stream))
                     || (volIndex < audioService.getStreamMinVolume(stream))) {
                 cmd.showError(String.format("Error: invalid volume index %d for stream %d "
-                        + "(should be in [%d..%d])", volIndex, stream,
+                                + "(should be in [%d..%d])", volIndex, stream,
                         audioService.getStreamMinVolume(stream),
                         audioService.getStreamMaxVolume(stream)));
                 return;
@@ -149,7 +144,7 @@
 
         //----------------------------------------
         // Non-interactive test
-        final int flag = showUi? AudioManager.FLAG_SHOW_UI : 0;
+        final int flag = showUi ? AudioManager.FLAG_SHOW_UI : 0;
         final String pack = cmd.getClass().getPackage().getName();
         if (mode == VOLUME_CONTROL_MODE_SET) {
             audioService.setStreamVolume(stream, volIndex, flag, pack/*callingPackage*/);
@@ -157,9 +152,9 @@
             audioService.adjustStreamVolume(stream, adjDir, flag, pack);
         }
         if (doGet) {
-            log(LOG_V, "volume is " + audioService.getStreamVolume(stream) +
-                       " in range [" + audioService.getStreamMinVolume(stream) +
-                       ".." + audioService.getStreamMaxVolume(stream) + "]");
+            log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
+                    + " in range [" + audioService.getStreamMinVolume(stream)
+                    + ".." + audioService.getStreamMaxVolume(stream) + "]");
         }
     }
 
@@ -181,5 +176,4 @@
             return "invalid stream";
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b57bfa0..e968fb70 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1289,6 +1289,18 @@
         return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
     }
 
+    public boolean hasUndecoratedRemoteView() {
+        Notification notification = getNotification();
+        Class<? extends Notification.Style> style = notification.getNotificationStyle();
+        boolean hasDecoratedStyle = style != null
+                && (Notification.DecoratedCustomViewStyle.class.equals(style)
+                || Notification.DecoratedMediaCustomViewStyle.class.equals(style));
+        boolean hasCustomRemoteView = notification.contentView != null
+                || notification.bigContentView != null
+                || notification.headsUpContentView != null;
+        return hasCustomRemoteView && !hasDecoratedStyle;
+    }
+
     @VisibleForTesting
     static final class Light {
         public final int color;
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index ac8d1a9..d1fe0d9 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -149,7 +149,7 @@
             stats.numPostedByApp++;
             stats.updateInterarrivalEstimate(now);
             stats.countApiUse(notification);
-            stats.numUndecoratedRemoteViews += (isUndecoratedRemoteView(notification) ? 1 : 0);
+            stats.numUndecoratedRemoteViews += (notification.hasUndecoratedRemoteView() ? 1 : 0);
         }
         releaseAggregatedStatsLocked(aggregatedStatsArray);
         if (ENABLE_SQLITE_LOG) {
@@ -158,13 +158,6 @@
     }
 
     /**
-     * Does this notification use RemoveViews without a platform decoration?
-     */
-    protected static boolean isUndecoratedRemoteView(NotificationRecord notification) {
-        return (notification.getNotification().getNotificationStyle() == null);
-    }
-
-    /**
      * Called when a notification has been updated.
      */
     public synchronized void registerUpdatedByApp(NotificationRecord notification,
@@ -1303,7 +1296,7 @@
             } else {
                 putPosttimeVisibility(r, cv);
             }
-            cv.put(COL_UNDECORATED, (isUndecoratedRemoteView(r) ? 1 : 0));
+            cv.put(COL_UNDECORATED, (r.hasUndecoratedRemoteView() ? 1 : 0));
             SQLiteDatabase db = mHelper.getWritableDatabase();
             if (db.insert(TAB_LOG, null, cv) < 0) {
                 Log.wtf(TAG, "Error while trying to insert values: " + cv);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 2b4b409..5ae8c58 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -17,11 +17,11 @@
 package com.android.server.pm;
 
 import android.annotation.IntDef;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
 import android.apex.IApexService;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -176,13 +176,9 @@
      * enough for it to be activated at the next boot, the caller needs to call
      * {@link #markStagedSessionReady(int)}.
      *
-     * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
-     * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
-     *                        an array of identifiers of all the child sessions. Otherwise it should
-     *                        be an empty array.
      * @throws PackageManagerException if call to apexd fails
      */
-    abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+    abstract ApexInfoList submitStagedSession(ApexSessionParams params)
             throws PackageManagerException;
 
     /**
@@ -450,11 +446,10 @@
         }
 
         @Override
-        ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
-                throws PackageManagerException {
+        ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
             try {
                 final ApexInfoList apexInfoList = new ApexInfoList();
-                mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+                mApexService.submitStagedSession(params, apexInfoList);
                 return apexInfoList;
             } catch (RemoteException re) {
                 Slog.e(TAG, "Unable to contact apexservice", re);
@@ -686,7 +681,7 @@
         }
 
         @Override
-        ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
+        ApexInfoList submitStagedSession(ApexSessionParams params)
                 throws PackageManagerException {
             throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                     "Device doesn't support updating APEX");
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index f2a2e65..13bd7e5 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -627,11 +627,13 @@
         final int providersSize = ArrayUtils.size(pkg.getProviders());
         StringBuilder r = null;
         for (int i = 0; i < providersSize; i++) {
-            EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i));
+            ParsedProvider p = pkg.getProviders().get(i);
             mProviders.addProvider(p);
             if (p.getAuthority() != null) {
                 String[] names = p.getAuthority().split(";");
-                p.setEffectiveAuthority(null);
+
+                // TODO(b/135203078): Remove this mutation
+                p.setAuthority(null);
                 for (int j = 0; j < names.length; j++) {
                     if (j == 1 && p.isSyncable()) {
                         // We only want the first authority for a provider to possibly be
@@ -641,15 +643,15 @@
                         // to a provider that we don't want to change.
                         // Only do this for the second authority since the resulting provider
                         // object can be the same for all future authorities for this provider.
-                        p = new EffectiveProvider(p);
-                        p.setEffectiveSyncable(false);
+                        p = new ParsedProvider(p);
+                        p.setSyncable(false);
                     }
                     if (!mProvidersByAuthority.containsKey(names[j])) {
                         mProvidersByAuthority.put(names[j], p);
                         if (p.getAuthority() == null) {
-                            p.setEffectiveAuthority(names[j]);
+                            p.setAuthority(names[j]);
                         } else {
-                            p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]);
+                            p.setAuthority(p.getAuthority() + ";" + names[j]);
                         }
                         if (DEBUG_PACKAGE_SCANNING && chatty) {
                             Log.d(TAG, "Registered content provider: " + names[j]
@@ -2113,35 +2115,4 @@
             return info.authoritiesIterator();
         }
     }
-
-    // TODO(b/135203078): Document or remove this if possible.
-    class EffectiveProvider extends ParsedProvider {
-
-        private String mEffectiveAuthority;
-        private boolean mEffectiveSyncable;
-
-        public EffectiveProvider(ParsedProvider parsedProvider) {
-            this.setFrom(parsedProvider);
-            this.mEffectiveAuthority = parsedProvider.getAuthority();
-            this.mEffectiveSyncable = parsedProvider.isSyncable();
-        }
-
-        public void setEffectiveAuthority(String authority) {
-            this.mEffectiveAuthority = authority;
-        }
-
-        public void setEffectiveSyncable(boolean syncable) {
-            this.mEffectiveSyncable = syncable;
-        }
-
-        @Override
-        public String getAuthority() {
-            return mEffectiveAuthority;
-        }
-
-        @Override
-        public boolean isSyncable() {
-            return mEffectiveSyncable;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 642b500..17b1daf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13487,10 +13487,12 @@
             }
             Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
             try {
-                if (bm.isBackupServiceActive(userId)) {
+                if (bm.isUserReadyForBackup(userId)) {
                     bm.restoreAtInstallForUser(
                             userId, res.pkg.getAppInfoPackageName(), token);
                 } else {
+                    Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
+                            + "didn't take place.");
                     return false;
                 }
             } catch (RemoteException e) {
@@ -14144,7 +14146,7 @@
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
 
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
-                            installSource.installerPackageName);
+                            installSource.initiatingPackageName);
 
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                             installFlags);
@@ -15707,7 +15709,9 @@
                 // TODO(patb): create a more descriptive reason than unknown in future release
                 // mark all non-failure installs as UNKNOWN so we do not treat them as success
                 for (InstallRequest request : requests) {
-                    request.installResult.freezer.close();
+                    if (request.installResult.freezer != null) {
+                        request.installResult.freezer.close();
+                    }
                     if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                         request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
                     }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 7ea4e98..688c34f 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -21,6 +21,7 @@
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -36,6 +37,8 @@
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.ParceledListSlice;
 import android.content.rollback.IRollbackManager;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -49,6 +52,7 @@
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.GuardedBy;
@@ -82,6 +86,9 @@
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
+    @GuardedBy("mStagedSessions")
+    private final SparseIntArray mSessionRollbackIds = new SparseIntArray();
+
     StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
         mPi = pi;
         mApexManager = am;
@@ -166,18 +173,32 @@
 
     private List<PackageInfo> submitSessionToApexService(
             @NonNull PackageInstallerSession session) throws PackageManagerException {
-        final IntArray childSessionsIds = new IntArray();
+        final IntArray childSessionIds = new IntArray();
         if (session.isMultiPackage()) {
             for (int id : session.getChildSessionIds()) {
                 if (isApexSession(mStagedSessions.get(id))) {
-                    childSessionsIds.add(id);
+                    childSessionIds.add(id);
+                }
+            }
+        }
+        ApexSessionParams apexSessionParams = new ApexSessionParams();
+        apexSessionParams.sessionId = session.sessionId;
+        apexSessionParams.childSessionIds = childSessionIds.toArray();
+        if (session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {
+            apexSessionParams.isRollback = true;
+            apexSessionParams.rollbackId = retrieveRollbackIdForCommitSession(session.sessionId);
+        } else {
+            synchronized (mStagedSessions) {
+                int rollbackId = mSessionRollbackIds.get(session.sessionId, -1);
+                if (rollbackId != -1) {
+                    apexSessionParams.hasRollbackEnabled = true;
+                    apexSessionParams.rollbackId = rollbackId;
                 }
             }
         }
         // submitStagedSession will throw a PackageManagerException if apexd verification fails,
         // which will be propagated to populate stagedSessionErrorMessage of this session.
-        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
-                childSessionsIds.toArray());
+        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams);
         final List<PackageInfo> result = new ArrayList<>();
         for (ApexInfo apexInfo : apexInfoList.apexInfos) {
             final PackageInfo packageInfo;
@@ -208,6 +229,19 @@
         return result;
     }
 
+    private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException {
+        RollbackManager rm = mContext.getSystemService(RollbackManager.class);
+
+        List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks();
+        for (RollbackInfo rollback : rollbacks) {
+            if (rollback.getCommittedSessionId() == sessionId) {
+                return rollback.getRollbackId();
+            }
+        }
+        throw new PackageManagerException(
+                "Could not find rollback id for commit session: " + sessionId);
+    }
+
     private void checkRequiredVersionCode(final PackageInstallerSession session,
             final PackageInfo activePackage) throws PackageManagerException {
         if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) {
@@ -633,6 +667,7 @@
     void abortSession(@NonNull PackageInstallerSession session) {
         synchronized (mStagedSessions) {
             mStagedSessions.remove(session.sessionId);
+            mSessionRollbackIds.delete(session.sessionId);
         }
     }
 
@@ -865,6 +900,28 @@
          */
         private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
             Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
+
+            if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+                // If rollback is enabled for this session, we call through to the RollbackManager
+                // with the list of sessions it must enable rollback for. Note that
+                // notifyStagedSession is a synchronous operation.
+                final IRollbackManager rm = IRollbackManager.Stub.asInterface(
+                        ServiceManager.getService(Context.ROLLBACK_SERVICE));
+                try {
+                    // NOTE: To stay consistent with the non-staged install flow, we don't fail the
+                    // entire install if rollbacks can't be enabled.
+                    int rollbackId = rm.notifyStagedSession(session.sessionId);
+                    if (rollbackId != -1) {
+                        synchronized (mStagedSessions) {
+                            mSessionRollbackIds.put(session.sessionId, rollbackId);
+                        }
+                    }
+                } catch (RemoteException re) {
+                    Slog.e(TAG, "Failed to notifyStagedSession for session: "
+                            + session.sessionId, re);
+                }
+            }
+
             notifyPreRebootVerification_Start_Complete(session.sessionId);
         }
 
@@ -929,25 +986,6 @@
          * </ul></p>
          */
         private void handlePreRebootVerification_End(@NonNull PackageInstallerSession session) {
-            if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
-                // If rollback is enabled for this session, we call through to the RollbackManager
-                // with the list of sessions it must enable rollback for. Note that
-                // notifyStagedSession is a synchronous operation.
-                final IRollbackManager rm = IRollbackManager.Stub.asInterface(
-                        ServiceManager.getService(Context.ROLLBACK_SERVICE));
-                try {
-                    // NOTE: To stay consistent with the non-staged install flow, we don't fail the
-                    // entire install if rollbacks can't be enabled.
-                    if (!rm.notifyStagedSession(session.sessionId)) {
-                        Slog.e(TAG, "Unable to enable rollback for session: "
-                                + session.sessionId);
-                    }
-                } catch (RemoteException re) {
-                    Slog.e(TAG, "Failed to notifyStagedSession for session: "
-                            + session.sessionId, re);
-                }
-            }
-
             // Proactively mark session as ready before calling apexd. Although this call order
             // looks counter-intuitive, this is the easiest way to ensure that session won't end up
             // in the inconsistent state:
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index ad4411c..4d436c0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -579,15 +579,6 @@
             applyUserRestrictionsLR(UserHandle.USER_SYSTEM);
         }
 
-        UserInfo currentGuestUser = findCurrentGuestUser();
-        if (currentGuestUser != null && !hasUserRestriction(
-                UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
-            // If a guest user currently exists, apply the DISALLOW_CONFIG_WIFI option
-            // to it, in case this guest was created in a previous version where this
-            // user restriction was not a default guest restriction.
-            setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
-        }
-
         mContext.registerReceiver(mDisableQuietModeCallback,
                 new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
                 null, mHandler);
@@ -1118,11 +1109,6 @@
             info.flags ^= UserInfo.FLAG_ADMIN;
             writeUserLP(getUserDataLU(info.id));
         }
-
-        // Remove non-admin restrictions.
-        // Keep synchronized with createUserEvenWhenDisallowed.
-        setUserRestriction(UserManager.DISALLOW_SMS, false, userId);
-        setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, userId);
     }
 
     /**
@@ -1602,10 +1588,12 @@
     private void initDefaultGuestRestrictions() {
         synchronized (mGuestRestrictions) {
             if (mGuestRestrictions.isEmpty()) {
-                mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
-                mGuestRestrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
-                mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
-                mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
+                UserTypeDetails guestType = mUserTypes.get(UserManager.USER_TYPE_FULL_GUEST);
+                if (guestType == null) {
+                    Slog.wtf(LOG_TAG, "Can't set default guest restrictions: type doesn't exist.");
+                    return;
+                }
+                guestType.addDefaultRestrictionsTo(mGuestRestrictions);
             }
         }
     }
@@ -2494,6 +2482,12 @@
                         mDevicePolicyLocalUserRestrictions, mDevicePolicyGlobalUserRestrictions
                 );
             }
+            // DISALLOW_CONFIG_WIFI was made a default guest restriction some time during version 6.
+            final UserInfo currentGuestUser = findCurrentGuestUser();
+            if (currentGuestUser != null && !hasUserRestriction(
+                    UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) {
+                setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
+            }
             userVersion = 7;
         }
 
@@ -3245,12 +3239,15 @@
                 writeUserLP(userData);
             }
             updateUserIds();
+
             Bundle restrictions = new Bundle();
-            // TODO(b/142482943): Generalize this using UserTypeDetails default restrictions.
             if (isGuest) {
+                // Guest default restrictions can be modified via setDefaultGuestRestrictions.
                 synchronized (mGuestRestrictions) {
                     restrictions.putAll(mGuestRestrictions);
                 }
+            } else {
+                userTypeDetails.addDefaultRestrictionsTo(restrictions);
             }
             synchronized (mRestrictionsLock) {
                 mBaseUserRestrictions.append(userId, restrictions);
@@ -4666,14 +4663,8 @@
         @Override
         public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
                 @UserInfoFlag int flags, String[] disallowedPackages) {
-            UserInfo user = createUserInternalUnchecked(name, userType, flags,
+            return createUserInternalUnchecked(name, userType, flags,
                     UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages);
-            // Keep this in sync with UserManager.createUser
-            if (user != null && !user.isAdmin() && !user.isDemo()) {
-                setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
-                setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, true, user.id);
-            }
-            return user;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 1631df3..826cd3f7 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -19,18 +19,17 @@
 import android.annotation.ColorRes;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.content.pm.UserInfo;
 import android.content.pm.UserInfo.UserInfoFlag;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.UserManager;
 
 import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * Contains the details about a multiuser "user type", such as a
@@ -75,8 +74,13 @@
     /** The {@link UserInfo.UserInfoFlag}s that all users of this type will automatically have. */
     private final @UserInfoFlag int mDefaultUserInfoPropertyFlags;
 
-    // TODO(b/142482943): Hook these up to something and set them for each type.
-    private final List<String> mDefaultRestrictions;
+    /**
+     * List of User Restrictions to apply by default to newly created users of this type.
+     * <p>Does not apply to SYSTEM users (since they are not formally created); for them use
+     * {@link com.android.internal.R.array#config_defaultFirstUserRestrictions} instead.
+     * The Bundle is of the form used by {@link UserRestrictionsUtils}.
+     */
+    private final @Nullable Bundle mDefaultRestrictions;
 
 
     // Fields for profiles only, controlling the nature of their badges.
@@ -99,7 +103,7 @@
      *
      * <p>Must be set if mIconBadge is set.
      */
-    private final int[] mBadgeLabels;
+    private final @Nullable int[] mBadgeLabels;
 
     /**
      * Resource ID ({@link ColorRes}) of the colors badge put on icons.
@@ -110,22 +114,21 @@
      *
      * <p>Must be set if mIconBadge is set.
      */
-    private final int[] mBadgeColors;
+    private final @Nullable int[] mBadgeColors;
 
     private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
             @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
             int maxAllowedPerParent,
             int iconBadge, int badgePlain, int badgeNoBackground,
-            int[] badgeLabels, int[] badgeColors,
-            ArrayList<String> defaultRestrictions) {
+            @Nullable int[] badgeLabels, @Nullable int[] badgeColors,
+            @Nullable Bundle defaultRestrictions) {
         this.mName = name;
         this.mEnabled = enabled;
         this.mMaxAllowed = maxAllowed;
         this.mMaxAllowedPerParent = maxAllowedPerParent;
         this.mBaseType = baseType;
         this.mDefaultUserInfoPropertyFlags = defaultUserInfoPropertyFlags;
-        this.mDefaultRestrictions =
-                Collections.unmodifiableList(new ArrayList<>(defaultRestrictions));
+        this.mDefaultRestrictions = defaultRestrictions;
 
         this.mIconBadge = iconBadge;
         this.mBadgePlain = badgePlain;
@@ -180,7 +183,7 @@
         return mIconBadge != Resources.ID_NULL;
     }
 
-    /** Resource ID of the badge put on icons. */
+    /** Resource ID of the badge to put on icons. */
     public @DrawableRes int getIconBadge() {
         return mIconBadge;
     }
@@ -231,9 +234,14 @@
         return (mBaseType & UserInfo.FLAG_SYSTEM) != 0;
     }
 
-    // TODO(b/142482943): Hook this up and don't return the original.
-    public List<String> getDefaultRestrictions() {
-        return mDefaultRestrictions;
+    /** Returns a Bundle representing the default user restrictions. */
+    @NonNull Bundle getDefaultRestrictions() {
+        return UserRestrictionsUtils.clone(mDefaultRestrictions);
+    }
+
+    /** Adds the default user restrictions to the given bundle of restrictions. */
+    public void addDefaultRestrictionsTo(@NonNull Bundle currentRestrictions) {
+        UserRestrictionsUtils.merge(currentRestrictions, mDefaultRestrictions);
     }
 
     /** Dumps details of the UserTypeDetails. Do not parse this. */
@@ -247,7 +255,8 @@
         pw.print(prefix); pw.print("mDefaultUserInfoFlags: ");
         pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
         pw.print(prefix); pw.print("mLabel: "); pw.println(mLabel);
-        pw.print(prefix); pw.print("mDefaultRestrictions: "); pw.println(mDefaultRestrictions);
+        pw.print(prefix); pw.println("mDefaultRestrictions: ");
+        UserRestrictionsUtils.dumpRestrictions(pw, prefix + "    ", mDefaultRestrictions);
         pw.print(prefix); pw.print("mIconBadge: "); pw.println(mIconBadge);
         pw.print(prefix); pw.print("mBadgePlain: "); pw.println(mBadgePlain);
         pw.print(prefix); pw.print("mBadgeNoBackground: "); pw.println(mBadgeNoBackground);
@@ -265,14 +274,14 @@
         private int mMaxAllowed = UNLIMITED_NUMBER_OF_USERS;
         private int mMaxAllowedPerParent = UNLIMITED_NUMBER_OF_USERS;
         private int mDefaultUserInfoPropertyFlags = 0;
-        private ArrayList<String> mDefaultRestrictions = new ArrayList<>();
+        private @Nullable Bundle mDefaultRestrictions = null;
         private boolean mEnabled = true;
         private int mLabel = Resources.ID_NULL;
-        private int[] mBadgeLabels = null;
-        private int[] mBadgeColors = null;
-        private int mIconBadge = Resources.ID_NULL;
-        private int mBadgePlain = Resources.ID_NULL;
-        private int mBadgeNoBackground = Resources.ID_NULL;
+        private @Nullable int[] mBadgeLabels = null;
+        private @Nullable int[] mBadgeColors = null;
+        private @DrawableRes int mIconBadge = Resources.ID_NULL;
+        private @DrawableRes int mBadgePlain = Resources.ID_NULL;
+        private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
 
         public Builder setName(String name) {
             mName = name;
@@ -304,27 +313,27 @@
             return this;
         }
 
-        public Builder setBadgeLabels(int ... badgeLabels) {
+        public Builder setBadgeLabels(@StringRes int ... badgeLabels) {
             mBadgeLabels = badgeLabels;
             return this;
         }
 
-        public Builder setBadgeColors(int ... badgeColors) {
+        public Builder setBadgeColors(@ColorRes int ... badgeColors) {
             mBadgeColors = badgeColors;
             return this;
         }
 
-        public Builder setIconBadge(int badgeIcon) {
+        public Builder setIconBadge(@DrawableRes int badgeIcon) {
             mIconBadge = badgeIcon;
             return this;
         }
 
-        public Builder setBadgePlain(int badgePlain) {
+        public Builder setBadgePlain(@DrawableRes int badgePlain) {
             mBadgePlain = badgePlain;
             return this;
         }
 
-        public Builder setBadgeNoBackground(int badgeNoBackground) {
+        public Builder setBadgeNoBackground(@DrawableRes int badgeNoBackground) {
             mBadgeNoBackground = badgeNoBackground;
             return this;
         }
@@ -334,11 +343,15 @@
             return this;
         }
 
-        public Builder setDefaultRestrictions(ArrayList<String> restrictions) {
+        public Builder setDefaultRestrictions(@Nullable Bundle restrictions) {
             mDefaultRestrictions = restrictions;
             return this;
         }
 
+        @UserInfoFlag int getBaseType() {
+            return mBaseType;
+        }
+
         public UserTypeDetails createUserTypeDetails() {
             Preconditions.checkArgument(mName != null,
                     "Cannot create a UserTypeDetails with no name.");
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 43bbab1..7d45516 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -34,18 +34,36 @@
 
 import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS;
 
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
 import android.os.UserManager;
 import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.function.Consumer;
 
 /**
  * Class for creating all {@link UserTypeDetails} on the device.
  *
+ * This class is responsible both for defining the AOSP use types, as well as reading in customized
+ * user types from {@link com.android.internal.R.xml#config_user_types}.
+ *
  * Tests are located in UserManagerServiceUserTypeTest.java.
  * @hide
  */
 public final class UserTypeFactory {
 
+    private static final String LOG_TAG = "UserTypeFactory";
+
     /** This is a utility class, so no instantiable constructor. */
     private UserTypeFactory() {}
 
@@ -55,21 +73,25 @@
      * @return mapping from the name of each user type to its {@link UserTypeDetails} object
      */
     public static ArrayMap<String, UserTypeDetails> getUserTypes() {
-        final ArrayMap<String, UserTypeDetails> map = new ArrayMap<>();
-        // TODO(b/142482943): Read an xml file for OEM customized types.
-        //                    Remember to disallow "android." namespace
-        // TODO(b/142482943): Read an xml file to get any overrides for the built-in types.
-        final int maxManagedProfiles = 1;
-        map.put(USER_TYPE_PROFILE_MANAGED,
-                getDefaultTypeProfileManaged().setMaxAllowedPerParent(maxManagedProfiles)
-                        .createUserTypeDetails());
-        map.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeSystemFull().createUserTypeDetails());
-        map.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary().createUserTypeDetails());
-        map.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest().createUserTypeDetails());
-        map.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo().createUserTypeDetails());
-        map.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted().createUserTypeDetails());
-        map.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless().createUserTypeDetails());
-        return map;
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged());
+        builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem());
+        builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary());
+        builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest());
+        builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
+        builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
+        builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+
+        try (XmlResourceParser parser =
+                     Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
+            customizeBuilders(builders, parser);
+        }
+
+        final ArrayMap<String, UserTypeDetails> types = new ArrayMap<>(builders.size());
+        for (int i = 0; i < builders.size(); i++) {
+            types.put(builders.keyAt(i), builders.valueAt(i).createUserTypeDetails());
+        }
+        return types;
     }
 
     /**
@@ -93,7 +115,8 @@
                 .setBadgeColors(
                         com.android.internal.R.color.profile_badge_1,
                         com.android.internal.R.color.profile_badge_2,
-                        com.android.internal.R.color.profile_badge_3);
+                        com.android.internal.R.color.profile_badge_3)
+                .setDefaultRestrictions(null);
     }
 
     /**
@@ -104,7 +127,8 @@
         return new UserTypeDetails.Builder()
                 .setName(USER_TYPE_FULL_SECONDARY)
                 .setBaseType(FLAG_FULL)
-                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS);
+                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS)
+                .setDefaultRestrictions(getDefaultSecondaryUserRestrictions());
     }
 
     /**
@@ -115,13 +139,12 @@
                 .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
         final int flags = FLAG_GUEST | (ephemeralGuests ? FLAG_EPHEMERAL : 0);
 
-        // TODO(b/142482943): Put UMS.initDefaultGuestRestrictions() here; then fetch them from here
-
         return new UserTypeDetails.Builder()
                 .setName(USER_TYPE_FULL_GUEST)
                 .setBaseType(FLAG_FULL)
                 .setDefaultUserInfoPropertyFlags(flags)
-                .setMaxAllowed(1);
+                .setMaxAllowed(1)
+                .setDefaultRestrictions(getDefaultGuestUserRestrictions());
     }
 
     /**
@@ -132,7 +155,8 @@
                 .setName(USER_TYPE_FULL_DEMO)
                 .setBaseType(FLAG_FULL)
                 .setDefaultUserInfoPropertyFlags(FLAG_DEMO)
-                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS);
+                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS)
+                .setDefaultRestrictions(null);
     }
 
     /**
@@ -144,13 +168,15 @@
                 .setName(USER_TYPE_FULL_RESTRICTED)
                 .setBaseType(FLAG_FULL)
                 .setDefaultUserInfoPropertyFlags(FLAG_RESTRICTED)
-                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS);
+                .setMaxAllowed(UNLIMITED_NUMBER_OF_USERS)
+                // NB: UserManagerService.createRestrictedProfile() applies hardcoded restrictions.
+                .setDefaultRestrictions(null);
     }
 
     /**
      * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SYSTEM} configuration.
      */
-    private static UserTypeDetails.Builder getDefaultTypeSystemFull() {
+    private static UserTypeDetails.Builder getDefaultTypeFullSystem() {
         return new UserTypeDetails.Builder()
                 .setName(USER_TYPE_FULL_SYSTEM)
                 .setBaseType(FLAG_SYSTEM | FLAG_FULL);
@@ -165,4 +191,193 @@
                 .setName(USER_TYPE_SYSTEM_HEADLESS)
                 .setBaseType(FLAG_SYSTEM);
     }
+
+    private static Bundle getDefaultSecondaryUserRestrictions() {
+        final Bundle restrictions = new Bundle();
+        restrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
+        restrictions.putBoolean(UserManager.DISALLOW_SMS, true);
+        return restrictions;
+    }
+
+    private static Bundle getDefaultGuestUserRestrictions() {
+        // Guest inherits the secondary user's restrictions, plus has some extra ones.
+        final Bundle restrictions = getDefaultSecondaryUserRestrictions();
+        restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true);
+        restrictions.putBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
+        return restrictions;
+    }
+
+    /**
+     * Reads the given xml parser to obtain device user-type customization, and updates the given
+     * map of {@link UserTypeDetails.Builder}s accordingly.
+     * <p>
+     * The xml file can specify the attributes according to the set... methods below.
+     */
+    @VisibleForTesting
+    static void customizeBuilders(ArrayMap<String, UserTypeDetails.Builder> builders,
+            XmlResourceParser parser) {
+        try {
+            XmlUtils.beginDocument(parser, "user-types");
+            for (XmlUtils.nextElement(parser);
+                    parser.getEventType() != XmlResourceParser.END_DOCUMENT;
+                    XmlUtils.nextElement(parser)) {
+                final boolean isProfile;
+                final String elementName = parser.getName();
+                if ("profile-type".equals(elementName)) {
+                    isProfile = true;
+                } else if ("full-type".equals(elementName)) {
+                    isProfile = false;
+                } else {
+                    Slog.w(LOG_TAG, "Skipping unknown element " + elementName + " in "
+                                + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+
+                String typeName = parser.getAttributeValue(null, "name");
+                if (typeName == null) {
+                    Slog.w(LOG_TAG, "Skipping user type with no name in "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+                typeName.intern();
+
+                UserTypeDetails.Builder builder;
+                if (typeName.startsWith("android.")) {
+                    // typeName refers to a AOSP-defined type which we are modifying.
+                    Slog.i(LOG_TAG, "Customizing user type " + typeName);
+                    builder = builders.get(typeName);
+                    if (builder == null) {
+                        throw new IllegalArgumentException("Illegal custom user type name "
+                                + typeName + ": Non-AOSP user types cannot start with 'android.'");
+                    }
+                    final boolean isValid =
+                            (isProfile && builder.getBaseType() == UserInfo.FLAG_PROFILE)
+                            || (!isProfile && builder.getBaseType() == UserInfo.FLAG_FULL);
+                    if (!isValid) {
+                        throw new IllegalArgumentException("Wrong base type to customize user type "
+                                + "(" + typeName + "), which is type "
+                                + UserInfo.flagsToString(builder.getBaseType()));
+                    }
+                } else if (isProfile) {
+                    // typeName refers to a new OEM-defined profile type which we are defining.
+                    Slog.i(LOG_TAG, "Creating custom user type " + typeName);
+                    builder = new UserTypeDetails.Builder();
+                    builder.setName(typeName);
+                    builder.setBaseType(FLAG_PROFILE);
+                    builders.put(typeName, builder);
+                } else {
+                    throw new IllegalArgumentException("Creation of non-profile user type "
+                            + "(" + typeName + ") is not currently supported.");
+                }
+
+                // Process the attributes (other than name).
+                if (isProfile) {
+                    setIntAttribute(parser, "max-allowed-per-parent",
+                            builder::setMaxAllowedPerParent);
+                    setResAttribute(parser, "icon-badge", builder::setIconBadge);
+                    setResAttribute(parser, "badge-plain", builder::setBadgePlain);
+                    setResAttribute(parser, "badge-no-background", builder::setBadgeNoBackground);
+                }
+
+                // Process child elements.
+                final int depth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, depth)) {
+                    final String childName = parser.getName();
+                    if ("default-restrictions".equals(childName)) {
+                        final Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser);
+                        builder.setDefaultRestrictions(restrictions);
+                    } else if (isProfile && "badge-labels".equals(childName)) {
+                        setResAttributeArray(parser, builder::setBadgeLabels);
+                    } else if (isProfile && "badge-colors".equals(childName)) {
+                        setResAttributeArray(parser, builder::setBadgeColors);
+                    } else {
+                        Slog.w(LOG_TAG, "Unrecognized tag " + childName + " in "
+                                + parser.getPositionDescription());
+                    }
+                }
+            }
+        } catch (XmlPullParserException | IOException e) {
+            Slog.w(LOG_TAG, "Cannot read user type configuration file.", e);
+        }
+    }
+
+    /**
+     * If the given attribute exists, gets the int stored in it and performs the given fcn using it.
+     * The stored value must be an int or NumberFormatException will be thrown.
+     *
+     * @param parser xml parser from which to read the attribute
+     * @param attributeName name of the attribute
+     * @param fcn one-int-argument function,
+     *            like {@link UserTypeDetails.Builder#setMaxAllowedPerParent(int)}
+     */
+    private static void setIntAttribute(XmlResourceParser parser, String attributeName,
+            Consumer<Integer> fcn) {
+        final String intValue = parser.getAttributeValue(null, attributeName);
+        if (intValue == null) {
+            return;
+        }
+        try {
+            fcn.accept(Integer.parseInt(intValue));
+        } catch (NumberFormatException e) {
+            Slog.e(LOG_TAG, "Cannot parse value of '" + intValue + "' for " + attributeName
+                    + " in " + parser.getPositionDescription(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * If the given attribute exists, gets the resId stored in it (or 0 if it is not a valid resId)
+     * and performs the given fcn using it.
+     *
+     * @param parser xml parser from which to read the attribute
+     * @param attributeName name of the attribute
+     * @param fcn one-argument function, like {@link UserTypeDetails.Builder#setIconBadge(int)}
+     */
+    private static void setResAttribute(XmlResourceParser parser, String attributeName,
+            Consumer<Integer> fcn) {
+        if (parser.getAttributeValue(null, attributeName) == null) {
+            // Attribute is not present, i.e. use the default value.
+            return;
+        }
+        final int resId = parser.getAttributeResourceValue(null, attributeName, Resources.ID_NULL);
+        fcn.accept(resId);
+    }
+
+    /**
+     * Gets the resIds stored in "item" elements (in their "res" attribute) at the current depth.
+     * Then performs the given fcn using the int[] array of these resIds.
+     * <p>
+     * Each xml element is expected to be of the form {@code <item res="someResValue" />}.
+     *
+     * @param parser xml parser from which to read the elements and their attributes
+     * @param fcn function, like {@link UserTypeDetails.Builder#setBadgeColors(int...)}
+     */
+    private static void setResAttributeArray(XmlResourceParser parser, Consumer<int[]> fcn)
+            throws IOException, XmlPullParserException {
+
+        ArrayList<Integer> resList = new ArrayList<>();
+        final int depth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, depth)) {
+            final String elementName = parser.getName();
+            if (!"item".equals(elementName)) {
+                Slog.w(LOG_TAG, "Skipping unknown child element " + elementName + " in "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+            final int resId = parser.getAttributeResourceValue(null, "res", -1);
+            if (resId == -1) {
+                continue;
+            }
+            resList.add(resId);
+        }
+
+        int[] result = new int[resList.size()];
+        for (int i = 0; i < resList.size(); i++) {
+            result[i] = resList.get(i);
+        }
+        fcn.accept(result);
+    }
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8435a82..0d8f257 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -157,6 +157,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UEventObserver;
 import android.os.UserHandle;
 import android.os.VibrationEffect;
@@ -4603,6 +4604,7 @@
     public void screenTurningOn(final ScreenOnListener screenOnListener) {
         if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
 
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
         updateScreenOffSleepToken(false);
         mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
 
@@ -4665,6 +4667,7 @@
         if (!mDefaultDisplayPolicy.finishScreenTurningOn()) {
             return; // Spurious or not ready yet.
         }
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
 
         final boolean enableScreen;
         final boolean awake = mDefaultDisplayPolicy.isAwake();
@@ -4949,6 +4952,7 @@
                     mBootMsgDialog.getWindow().setDimAmount(1);
                     WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
                     lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+                    lp.setFitWindowInsetsTypes(0 /* types */);
                     mBootMsgDialog.getWindow().setAttributes(lp);
                     mBootMsgDialog.setCancelable(false);
                     mBootMsgDialog.show();
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 8b79c3f..6898e1c 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -418,6 +418,7 @@
                 if (isStaged()) {
                     parentParams.setStaged();
                 }
+                parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
 
                 int parentSessionId = packageInstaller.createSession(parentParams);
                 PackageInstaller.Session parentSession = packageInstaller.openSession(
@@ -484,6 +485,7 @@
                                 synchronized (mLock) {
                                     mState = ROLLBACK_STATE_AVAILABLE;
                                     mRestoreUserDataInProgress = false;
+                                    info.setCommittedSessionId(-1);
                                 }
                                 sendFailure(context, statusReceiver,
                                         RollbackManager.STATUS_FAILURE_INSTALL,
@@ -500,7 +502,6 @@
                                     mRestoreUserDataInProgress = false;
                                 }
 
-                                info.setCommittedSessionId(parentSessionId);
                                 info.getCausePackages().addAll(causePackages);
                                 RollbackStore.deletePackageCodePaths(this);
                                 RollbackStore.saveRollback(this);
@@ -528,6 +529,7 @@
                 );
 
                 mState = ROLLBACK_STATE_COMMITTED;
+                info.setCommittedSessionId(parentSessionId);
                 mRestoreUserDataInProgress = true;
                 parentSession.commit(receiver.getIntentSender());
             } catch (IOException e) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 3f5e2a4..9324870 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -897,11 +897,11 @@
     }
 
     @Override
-    public boolean notifyStagedSession(int sessionId) {
+    public int notifyStagedSession(int sessionId) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("notifyStagedSession may only be called by the system.");
         }
-        final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
+        final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>();
 
         // NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
         // to preserve the invariant that all operations that modify state happen there.
@@ -911,7 +911,7 @@
             final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
             if (session == null) {
                 Slog.e(TAG, "No matching install session for: " + sessionId);
-                result.offer(false);
+                result.offer(-1);
                 return;
             }
 
@@ -923,7 +923,7 @@
             if (!session.isMultiPackage()) {
                 if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
                     Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
-                    result.offer(false);
+                    result.offer(-1);
                     return;
                 }
             } else {
@@ -932,25 +932,30 @@
                             installer.getSessionInfo(childSessionId);
                     if (childSession == null) {
                         Slog.e(TAG, "No matching child install session for: " + childSessionId);
-                        result.offer(false);
+                        result.offer(-1);
                         return;
                     }
                     if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
                         Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
-                        result.offer(false);
+                        result.offer(-1);
                         return;
                     }
                 }
             }
 
-            result.offer(completeEnableRollback(newRollback, true) != null);
+            Rollback rollback = completeEnableRollback(newRollback, true);
+            if (rollback == null) {
+                result.offer(-1);
+            } else {
+                result.offer(rollback.info.getRollbackId());
+            }
         });
 
         try {
             return result.take();
         } catch (InterruptedException ie) {
             Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response");
-            return false;
+            return -1;
         }
     }
 
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 46dd366..aa3ab63 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -308,34 +308,6 @@
     }
 
     /**
-     * Throws an {@link IllegalStateException} if {@code path} is not ready to be accessed by
-     * {@code userId}.
-     */
-    // TODO(b/144332951): This is not used because it is racy. Right after checking a path
-    // we can call into vold with that path and the FUSE daemon can go down. Improve or remove
-    public void checkPathReadyForUser(int userId, String path) {
-        if (!mIsFuseEnabled) {
-            return;
-        }
-
-        if (mIsResetting) {
-            throw new IllegalStateException("Connection resetting for user " + userId
-                    + " with path " + path);
-        }
-
-        StorageUserConnection connection = null;
-        synchronized (mLock) {
-            connection = mConnections.get(userId);
-        }
-
-        if (connection == null) {
-            throw new IllegalStateException("Connection not ready for user " + userId
-                    + " with path " + path);
-        }
-        connection.checkPathReady(path);
-    }
-
-    /**
      * Returns {@code true} if {@code vol} is an emulated or public volume,
      * {@code false} otherwise
      **/
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 5c44eee..10514ad 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -163,20 +163,6 @@
         mActiveConnection.close();
     }
 
-    /** Throws an {@link IllegalArgumentException} if {@code path} is not ready for access */
-    public void checkPathReady(String path) {
-        synchronized (mLock) {
-            for (Session session : mSessions.values()) {
-                if (session.upperPath != null && path.startsWith(session.upperPath)) {
-                    if (mActiveConnection.isActiveLocked(session)) {
-                        return;
-                    }
-                }
-            }
-            throw new IllegalStateException("Path not ready " + path);
-        }
-    }
-
     /** Returns all created sessions. */
     public Set<String> getAllSessionIds() {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
old mode 100644
new mode 100755
index 8e66b14..18ed51a
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2943,6 +2943,16 @@
                 if (state != null) {
                     setStateLocked(inputId, state, mCurrentUserId);
                 }
+                UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
+                // Broadcast the event to all hardware inputs.
+                for (ServiceState serviceState : userState.serviceStateMap.values()) {
+                    if (!serviceState.isHardware || serviceState.service == null) continue;
+                    try {
+                        serviceState.service.notifyHdmiDeviceUpdated(deviceInfo);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "error in notifyHdmiDeviceUpdated", e);
+                    }
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
deleted file mode 100644
index 35b64e7..0000000
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ /dev/null
@@ -1,1384 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-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.os.Build.VERSION_CODES.N;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.FLAG_PRIVATE;
-import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
-
-import static com.android.server.am.ActivityDisplayProto.DISPLAY;
-import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityDisplayProto.ID;
-import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
-import static com.android.server.am.ActivityDisplayProto.STACKS;
-import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.RootActivityContainer.FindTaskResult;
-import static com.android.server.wm.RootActivityContainer.TAG_STATES;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
-import android.app.WindowConfiguration;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.IntArray;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.Display;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.function.pooled.PooledConsumer;
-import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledPredicate;
-import com.android.server.protolog.common.ProtoLog;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * Exactly one of these classes per Display in the system. Capable of holding zero or more
- * attached {@link ActivityStack}s.
- */
-class ActivityDisplay extends DisplayContent {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
-    private static final String TAG_STACK = TAG + POSTFIX_STACK;
-
-    static final int POSITION_TOP = Integer.MAX_VALUE;
-    static final int POSITION_BOTTOM = Integer.MIN_VALUE;
-
-    /**
-     * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
-     */
-    private static int sNextFreeStackId = 0;
-
-    private RootActivityContainer mRootActivityContainer;
-    /** Actual Display this object tracks. */
-    int mDisplayId;
-    Display mDisplay;
-
-    /**
-     * All of the stacks on this display. Order matters, topmost stack is in front of all other
-     * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
-     * changing the list should also call {@link #onStackOrderChanged()}.
-     */
-    private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
-
-    /** Array of all UIDs that are present on the display. */
-    private IntArray mDisplayAccessUIDs = new IntArray();
-
-    /** All tokens used to put activities on this stack to sleep (including mOffToken) */
-    final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
-    /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
-    ActivityTaskManagerInternal.SleepToken mOffToken;
-
-    private boolean mSleeping;
-
-    /** We started the process of removing the display from the system. */
-    private boolean mRemoving;
-
-    /**
-     * The display is removed from the system and we are just waiting for all activities on it to be
-     * finished before removing this object.
-     */
-    private boolean mRemoved;
-
-    /** The display can only contain one task. */
-    private boolean mSingleTaskInstance;
-
-    /**
-     * Non-null if the last size compatibility mode activity is using non-native screen
-     * configuration. The activity is not able to put in multi-window mode, so it exists only one
-     * per display.
-     */
-    private ActivityRecord mLastCompatModeActivity;
-
-    /**
-     * A focusable stack that is purposely to be positioned at the top. Although the stack may not
-     * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
-     * target stack properly when there are other focusable always-on-top stacks.
-     */
-    private ActivityStack mPreferredTopFocusableStack;
-
-    /**
-     * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
-     * stack has been resumed. If stacks are changing position this will hold the old stack until
-     * the new stack becomes resumed after which it will be set to current focused stack.
-     */
-    private ActivityStack mLastFocusedStack;
-
-    // Used in updating the display size
-    private Point mTmpDisplaySize = new Point();
-
-    // Used in updating override configurations
-    private final Configuration mTempConfig = new Configuration();
-
-    private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
-
-    ActivityDisplay(RootActivityContainer root, Display display) {
-        super(display, root.mWindowManager);
-        mRootActivityContainer = root;
-        mDisplayId = display.getDisplayId();
-        mDisplay = display;
-
-        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
-
-        mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
-
-        if (mWmService.mDisplayManagerInternal != null) {
-            mWmService.mDisplayManagerInternal
-                .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo());
-            configureDisplayPolicy();
-        }
-
-        reconfigureDisplayLocked();
-        onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
-        mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
-    }
-
-    void onDisplayChanged() {
-        // The window policy is responsible for stopping activities on the default display.
-        final int displayId = mDisplay.getDisplayId();
-        if (displayId != DEFAULT_DISPLAY) {
-            final int displayState = mDisplay.getState();
-            if (displayState == Display.STATE_OFF && mOffToken == null) {
-                mOffToken = mAtmService.acquireSleepToken("Display-off", displayId);
-            } else if (displayState == Display.STATE_ON && mOffToken != null) {
-                mOffToken.release();
-                mOffToken = null;
-            }
-        }
-
-        mDisplay.getRealSize(mTmpDisplaySize);
-        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
-        updateDisplayInfo();
-        mWmService.requestTraversal();
-    }
-
-    void addStack(ActivityStack stack, int position) {
-        setStackOnDisplay(stack, position);
-        positionStackAt(stack, position);
-        mAtmService.updateSleepIfNeededLocked();
-    }
-
-    void onStackRemoved(ActivityStack stack) {
-        if (DEBUG_STACK) {
-            Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
-        }
-        if (mPreferredTopFocusableStack == stack) {
-            mPreferredTopFocusableStack = null;
-        }
-        releaseSelfIfNeeded();
-        mAtmService.updateSleepIfNeededLocked();
-        onStackOrderChanged(stack);
-    }
-
-    void positionStackAtTop(ActivityStack stack, boolean includingParents) {
-        positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
-    }
-
-    void positionStackAtTop(ActivityStack stack, boolean includingParents,
-            String updateLastFocusedStackReason) {
-        positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
-    }
-
-    void positionStackAtBottom(ActivityStack stack) {
-        positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
-    }
-
-    void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
-        positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
-    }
-
-    private void positionStackAt(ActivityStack stack, int position) {
-        positionStackAt(stack, position, false /* includingParents */,
-                null /* updateLastFocusedStackReason */);
-    }
-
-    private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
-            String updateLastFocusedStackReason) {
-        // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
-        //       the position internally, also update the logic here
-        final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
-                ? getFocusedStack() : null;
-        final boolean wasContained = getIndexOf(stack) >= 0;
-        if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
-            throw new IllegalStateException(
-                    "positionStackAt: Can only have one task on display=" + this);
-        }
-
-        // Since positionChildAt() is called during the creation process of pinned stacks,
-        // ActivityStack#getStack() can be null.
-        positionStackAt(position, stack, includingParents);
-
-        // The insert position may be adjusted to non-top when there is always-on-top stack. Since
-        // the original position is preferred to be top, the stack should have higher priority when
-        // we are looking for top focusable stack. The condition {@code wasContained} restricts the
-        // preferred stack is set only when moving an existing stack to top instead of adding a new
-        // stack that may be too early (e.g. in the middle of launching or reparenting).
-        if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
-            mPreferredTopFocusableStack = stack;
-        } else if (mPreferredTopFocusableStack == stack) {
-            mPreferredTopFocusableStack = null;
-        }
-
-        if (updateLastFocusedStackReason != null) {
-            final ActivityStack currentFocusedStack = getFocusedStack();
-            if (currentFocusedStack != prevFocusedStack) {
-                mLastFocusedStack = prevFocusedStack;
-                EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
-                        currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
-                        mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
-                        updateLastFocusedStackReason);
-            }
-        }
-
-        onStackOrderChanged(stack);
-    }
-
-    ActivityStack getStack(int stackId) {
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getStackAt(i);
-            if (stack.mStackId == stackId) {
-                return stack;
-            }
-        }
-        return null;
-    }
-
-    boolean alwaysCreateStack(int windowingMode, int activityType) {
-        // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
-        // modes so that we can manage visual ordering and return types correctly.
-        return activityType == ACTIVITY_TYPE_STANDARD
-                && (windowingMode == WINDOWING_MODE_FULLSCREEN
-                || windowingMode == WINDOWING_MODE_FREEFORM
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-    }
-
-    /**
-     * Returns an existing stack compatible with the windowing mode and activity type or creates one
-     * if a compatible stack doesn't exist.
-     * @see #getStack(int, int)
-     * @see #createStack(int, int, boolean)
-     */
-    ActivityStack getOrCreateStack(int windowingMode, int activityType,
-            boolean onTop) {
-        if (!alwaysCreateStack(windowingMode, activityType)) {
-            ActivityStack stack = getStack(windowingMode, activityType);
-            if (stack != null) {
-                return stack;
-            }
-        }
-        return createStack(windowingMode, activityType, onTop);
-    }
-
-    /**
-     * Returns an existing stack compatible with the input params or creates one
-     * if a compatible stack doesn't exist.
-     * @see #getOrCreateStack(int, int, boolean)
-     */
-    ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
-            @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
-            boolean onTop) {
-        // First preference is the windowing mode in the activity options if set.
-        int windowingMode = (options != null)
-                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-        // Validate that our desired windowingMode will work under the current conditions.
-        // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
-        // it's display's windowing mode.
-        windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
-        return getOrCreateStack(windowingMode, activityType, onTop);
-    }
-
-    @VisibleForTesting
-    int getNextStackId() {
-        return sNextFreeStackId++;
-    }
-
-    /**
-     * Creates a stack matching the input windowing mode and activity type on this display.
-     * @param windowingMode The windowing mode the stack should be created in. If
-     *                      {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
-     *                      inherit it's parent's windowing mode.
-     * @param activityType The activityType the stack should be created in. If
-     *                     {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
-     *                     be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
-     * @param onTop If true the stack will be created at the top of the display, else at the bottom.
-     * @return The newly created stack.
-     */
-    ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
-
-        if (mSingleTaskInstance && getStackCount() > 0) {
-            // Create stack on default display instead since this display can only contain 1 stack.
-            // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
-            // this goes away once ActivityView is no longer using virtual displays.
-            return mRootActivityContainer.getDefaultDisplay().createStack(
-                    windowingMode, activityType, onTop);
-        }
-
-        if (activityType == ACTIVITY_TYPE_UNDEFINED) {
-            // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
-            // anything else should be passing it in anyways...
-            activityType = ACTIVITY_TYPE_STANDARD;
-        }
-
-        if (activityType != ACTIVITY_TYPE_STANDARD) {
-            // For now there can be only one stack of a particular non-standard activity type on a
-            // display. So, get that ignoring whatever windowing mode it is currently in.
-            ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
-            if (stack != null) {
-                throw new IllegalArgumentException("Stack=" + stack + " of activityType="
-                        + activityType + " already on display=" + this + ". Can't have multiple.");
-            }
-        }
-
-        if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
-                mAtmService.mSupportsSplitScreenMultiWindow,
-                mAtmService.mSupportsFreeformWindowManagement,
-                mAtmService.mSupportsPictureInPicture, activityType)) {
-            throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
-                    + windowingMode);
-        }
-
-        final int stackId = getNextStackId();
-        return createStackUnchecked(windowingMode, activityType, stackId, onTop);
-    }
-
-    @VisibleForTesting
-    ActivityStack createStackUnchecked(int windowingMode, int activityType,
-            int stackId, boolean onTop) {
-        if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
-            throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
-                    + "activity type.");
-        }
-        return new ActivityStack(this, stackId,
-                mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
-    }
-
-    /**
-     * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
-     * focusable and visible stack from the top of stacks in this display.
-     */
-    ActivityStack getFocusedStack() {
-        if (mPreferredTopFocusableStack != null) {
-            return mPreferredTopFocusableStack;
-        }
-
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getStackAt(i);
-            if (stack.isFocusableAndVisible()) {
-                return stack;
-            }
-        }
-
-        return null;
-    }
-
-    ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
-        final int currentWindowingMode = currentFocus != null
-                ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
-        ActivityStack candidate = null;
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getStackAt(i);
-            if (ignoreCurrent && stack == currentFocus) {
-                continue;
-            }
-            if (!stack.isFocusableAndVisible()) {
-                continue;
-            }
-
-            if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                    && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
-                // If the currently focused stack is in split-screen secondary we save off the
-                // top primary split-screen stack as a candidate for focus because we might
-                // prefer focus to move to an other stack to avoid primary split-screen stack
-                // overlapping with a fullscreen stack when a fullscreen stack is higher in z
-                // than the next split-screen stack. Assistant stack, I am looking at you...
-                // We only move the focus to the primary-split screen stack if there isn't a
-                // better alternative.
-                candidate = stack;
-                continue;
-            }
-            if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
-                // Use the candidate stack since we are now at the secondary split-screen.
-                return candidate;
-            }
-            return stack;
-        }
-        return candidate;
-    }
-
-    ActivityRecord getResumedActivity() {
-        final ActivityStack focusedStack = getFocusedStack();
-        if (focusedStack == null) {
-            return null;
-        }
-        // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
-        // Check if the focused stack has the resumed activity
-        ActivityRecord resumedActivity = focusedStack.getResumedActivity();
-        if (resumedActivity == null || resumedActivity.app == null) {
-            // If there is no registered resumed activity in the stack or it is not running -
-            // try to use previously resumed one.
-            resumedActivity = focusedStack.mPausingActivity;
-            if (resumedActivity == null || resumedActivity.app == null) {
-                // If previously resumed activity doesn't work either - find the topmost running
-                // activity that can be focused.
-                resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
-            }
-        }
-        return resumedActivity;
-    }
-
-    ActivityStack getLastFocusedStack() {
-        return mLastFocusedStack;
-    }
-
-    boolean allResumedActivitiesComplete() {
-        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
-            if (r != null && !r.isState(RESUMED)) {
-                return false;
-            }
-        }
-        final ActivityStack currentFocusedStack = getFocusedStack();
-        if (DEBUG_STACK) {
-            Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
-                    + mLastFocusedStack + " to=" + currentFocusedStack);
-        }
-        mLastFocusedStack = currentFocusedStack;
-        return true;
-    }
-
-    /**
-     * Pause all activities in either all of the stacks or just the back stacks. This is done before
-     * resuming a new activity and to make sure that previously active activities are
-     * paused in stacks that are no longer visible or in pinned windowing mode. This does not
-     * pause activities in visible stacks, so if an activity is launched within the same stack/task,
-     * then we should explicitly pause that stack's top activity.
-     * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
-     * @param resuming The resuming activity.
-     * @return {@code true} if any activity was paused as a result of this call.
-     */
-    boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
-        boolean someActivityPaused = false;
-        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getStackAt(stackNdx);
-            final ActivityRecord resumedActivity = stack.getResumedActivity();
-            if (resumedActivity != null
-                    && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
-                        || !stack.isFocusable())) {
-                if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
-                        " mResumedActivity=" + resumedActivity);
-                someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
-                        resuming);
-            }
-        }
-        return someActivityPaused;
-    }
-
-    /**
-     * Find task for putting the Activity in.
-     */
-    void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
-            FindTaskResult result) {
-        mTmpFindTaskResult.clear();
-        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getStackAt(stackNdx);
-            if (!r.hasCompatibleActivityType(stack)) {
-                if (DEBUG_TASKS) {
-                    Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
-                }
-                continue;
-            }
-
-            mTmpFindTaskResult.process(r, stack);
-            // It is possible to have tasks in multiple stacks with the same root affinity, so
-            // we should keep looking after finding an affinity match to see if there is a
-            // better match in another stack. Also, task affinity isn't a good enough reason
-            // to target a display which isn't the source of the intent, so skip any affinity
-            // matches not on the specified display.
-            if (mTmpFindTaskResult.mRecord != null) {
-                if (mTmpFindTaskResult.mIdealMatch) {
-                    result.setTo(mTmpFindTaskResult);
-                    return;
-                } else if (isPreferredDisplay) {
-                    // Note: since the traversing through the stacks is top down, the floating
-                    // tasks should always have lower priority than any affinity-matching tasks
-                    // in the fullscreen stacks
-                    result.setTo(mTmpFindTaskResult);
-                }
-            }
-        }
-    }
-
-    /**
-     * Removes stacks in the input windowing modes from the system if they are of activity type
-     * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
-     */
-    void removeStacksInWindowingModes(int... windowingModes) {
-        if (windowingModes == null || windowingModes.length == 0) {
-            return;
-        }
-
-        // Collect the stacks that are necessary to be removed instead of performing the removal
-        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
-        // stacks reordered.
-        final ArrayList<ActivityStack> stacks = new ArrayList<>();
-        for (int j = windowingModes.length - 1 ; j >= 0; --j) {
-            final int windowingMode = windowingModes[j];
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getStackAt(i);
-                if (!stack.isActivityTypeStandardOrUndefined()) {
-                    continue;
-                }
-                if (stack.getWindowingMode() != windowingMode) {
-                    continue;
-                }
-                stacks.add(stack);
-            }
-        }
-
-        for (int i = stacks.size() - 1; i >= 0; --i) {
-            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
-        }
-    }
-
-    void removeStacksWithActivityTypes(int... activityTypes) {
-        if (activityTypes == null || activityTypes.length == 0) {
-            return;
-        }
-
-        // Collect the stacks that are necessary to be removed instead of performing the removal
-        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
-        // stacks reordered.
-        final ArrayList<ActivityStack> stacks = new ArrayList<>();
-        for (int j = activityTypes.length - 1 ; j >= 0; --j) {
-            final int activityType = activityTypes[j];
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getStackAt(i);
-                if (stack.getActivityType() == activityType) {
-                    stacks.add(stack);
-                }
-            }
-        }
-
-        for (int i = stacks.size() - 1; i >= 0; --i) {
-            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
-        }
-    }
-
-    void onSplitScreenModeDismissed() {
-        mAtmService.deferWindowLayout();
-        try {
-            // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = getStackAt(i);
-                if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
-                    continue;
-                }
-                otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
-                        false /* showRecents */, false /* enteringSplitScreenMode */,
-                        true /* deferEnsuringVisibility */, false /* creating */);
-            }
-        } finally {
-            final ActivityStack topFullscreenStack =
-                    getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            final ActivityStack homeStack = getHomeStack();
-            if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
-                // Whenever split-screen is dismissed we want the home stack directly behind the
-                // current top fullscreen stack so it shows up when the top stack is finished.
-                // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
-                // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
-                // once we have that.
-                homeStack.moveToFront("onSplitScreenModeDismissed");
-                topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
-            }
-            mAtmService.continueWindowLayout();
-        }
-    }
-
-    void onSplitScreenModeActivated() {
-        mAtmService.deferWindowLayout();
-        try {
-            // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
-            final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = getStackAt(i);
-                if (otherStack == splitScreenPrimaryStack
-                        || !otherStack.affectedBySplitScreenResize()) {
-                    continue;
-                }
-                otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
-                        false /* animate */, false /* showRecents */,
-                        true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
-                        false /* creating */);
-            }
-        } finally {
-            mAtmService.continueWindowLayout();
-        }
-    }
-
-    /**
-     * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
-     * @param windowingMode The windowing mode we are checking support for.
-     * @param supportsMultiWindow If we should consider support for multi-window mode in general.
-     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
-     * @param supportsFreeform If we should consider support for freeform multi-window.
-     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
-     * @param activityType The activity type under consideration.
-     * @return true if the windowing mode is supported.
-     */
-    private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
-            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
-            int activityType) {
-
-        if (windowingMode == WINDOWING_MODE_UNDEFINED
-                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            return true;
-        }
-        if (!supportsMultiWindow) {
-            return false;
-        }
-
-        final int displayWindowingMode = getWindowingMode();
-        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-            return supportsSplitScreen
-                    && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
-                    // Freeform windows and split-screen windows don't mix well, so prevent
-                    // split windowing modes on freeform displays.
-                    && displayWindowingMode != WINDOWING_MODE_FREEFORM;
-        }
-
-        if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
-            return false;
-        }
-
-        if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
-     * display with the provided parameters.
-     *
-     * @param r The ActivityRecord in question.
-     * @param options Options to start with.
-     * @param task The task within-which the activity would start.
-     * @param activityType The type of activity to start.
-     * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
-     */
-    int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable Task task, int activityType) {
-
-        // First preference if the windowing mode in the activity options if set.
-        int windowingMode = (options != null)
-                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
-        // If windowing mode is unset, then next preference is the candidate task, then the
-        // activity record.
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            if (task != null) {
-                windowingMode = task.getWindowingMode();
-            }
-            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
-                windowingMode = r.getWindowingMode();
-            }
-            if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-                // Use the display's windowing mode.
-                windowingMode = getWindowingMode();
-            }
-        }
-        windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
-        return windowingMode != WINDOWING_MODE_UNDEFINED
-                ? windowingMode : WINDOWING_MODE_FULLSCREEN;
-    }
-
-    /**
-     * Check that the requested windowing-mode is appropriate for the specified task and/or activity
-     * on this display.
-     *
-     * @param windowingMode The windowing-mode to validate.
-     * @param r The {@link ActivityRecord} to check against.
-     * @param task The {@link Task} to check against.
-     * @param activityType An activity type.
-     * @return The provided windowingMode or the closest valid mode which is appropriate.
-     */
-    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
-            int activityType) {
-        // Make sure the windowing mode we are trying to use makes sense for what is supported.
-        boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
-        boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
-        boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
-        boolean supportsPip = mAtmService.mSupportsPictureInPicture;
-        if (supportsMultiWindow) {
-            if (task != null) {
-                supportsMultiWindow = task.isResizeable();
-                supportsSplitScreen = task.supportsSplitScreenWindowingMode();
-                // TODO: Do we need to check for freeform and Pip support here?
-            } else if (r != null) {
-                supportsMultiWindow = r.isResizeable();
-                supportsSplitScreen = r.supportsSplitScreenWindowingMode();
-                supportsFreeform = r.supportsFreeform();
-                supportsPip = r.supportsPictureInPicture();
-            }
-        }
-
-        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
-        if (!inSplitScreenMode
-                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
-            // Switch to the display's windowing mode if we are not in split-screen mode and we are
-            // trying to launch in split-screen secondary.
-            windowingMode = WINDOWING_MODE_UNDEFINED;
-        } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
-                        || windowingMode == WINDOWING_MODE_UNDEFINED)
-                && supportsSplitScreen) {
-            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-        }
-
-        if (windowingMode != WINDOWING_MODE_UNDEFINED
-                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
-                        supportsFreeform, supportsPip, activityType)) {
-            return windowingMode;
-        }
-        return WINDOWING_MODE_UNDEFINED;
-    }
-
-    boolean isTopStack(ActivityStack stack) {
-        return stack == getTopStack();
-    }
-
-    boolean isTopNotPinnedStack(ActivityStack stack) {
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack current = getStackAt(i);
-            if (!current.inPinnedWindowingMode()) {
-                return current == stack;
-            }
-        }
-        return false;
-    }
-
-    ActivityStack getTopStackInWindowingMode(int windowingMode) {
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack current = getStackAt(i);
-            if (windowingMode == current.getWindowingMode()) {
-                return current;
-            }
-        }
-        return null;
-    }
-
-    ActivityRecord topRunningActivity() {
-        return topRunningActivity(false /* considerKeyguardState */);
-    }
-
-    /**
-     * Returns the top running activity in the focused stack. In the case the focused stack has no
-     * such activity, the next focusable stack on this display is returned.
-     *
-     * @param considerKeyguardState Indicates whether the locked state should be considered. if
-     *                              {@code true} and the keyguard is locked, only activities that
-     *                              can be shown on top of the keyguard will be considered.
-     * @return The top running activity. {@code null} if none is available.
-     */
-    ActivityRecord topRunningActivity(boolean considerKeyguardState) {
-        ActivityRecord topRunning = null;
-        final ActivityStack focusedStack = getFocusedStack();
-        if (focusedStack != null) {
-            topRunning = focusedStack.topRunningActivity();
-        }
-
-        // Look in other focusable stacks.
-        if (topRunning == null) {
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getStackAt(i);
-                // Only consider focusable stacks other than the current focused one.
-                if (stack == focusedStack || !stack.isFocusable()) {
-                    continue;
-                }
-                topRunning = stack.topRunningActivity();
-                if (topRunning != null) {
-                    break;
-                }
-            }
-        }
-
-        // This activity can be considered the top running activity if we are not considering
-        // the locked state, the keyguard isn't locked, or we can show when locked.
-        if (topRunning != null && considerKeyguardState
-                && mRootActivityContainer.mStackSupervisor.getKeyguardController().isKeyguardLocked()
-                && !topRunning.canShowWhenLocked()) {
-            return null;
-        }
-
-        return topRunning;
-    }
-
-    boolean updateDisplayOverrideConfigurationLocked() {
-        Configuration values = new Configuration();
-        computeScreenConfiguration(values);
-
-        mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
-                ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,
-                mDisplayId));
-
-        Settings.System.clearConfiguration(values);
-        updateDisplayOverrideConfigurationLocked(values, null /* starting */,
-                false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
-        return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
-    }
-
-    /**
-     * Updates override configuration specific for the selected display. If no config is provided,
-     * new one will be computed in WM based on current display info.
-     */
-    boolean updateDisplayOverrideConfigurationLocked(Configuration values,
-            ActivityRecord starting, boolean deferResume,
-            ActivityTaskManagerService.UpdateConfigurationResult result) {
-
-        int changes = 0;
-        boolean kept = true;
-
-        mAtmService.deferWindowLayout();
-        try {
-            if (values != null) {
-                if (mDisplayId == DEFAULT_DISPLAY) {
-                    // Override configuration of the default display duplicates global config, so
-                    // we're calling global config update instead for default display. It will also
-                    // apply the correct override config.
-                    changes = mAtmService.updateGlobalConfigurationLocked(values,
-                            false /* initLocale */, false /* persistent */,
-                            UserHandle.USER_NULL /* userId */, deferResume);
-                } else {
-                    changes = performDisplayOverrideConfigUpdate(values, deferResume);
-                }
-            }
-
-            kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
-        } finally {
-            mAtmService.continueWindowLayout();
-        }
-
-        if (result != null) {
-            result.changes = changes;
-            result.activityRelaunched = !kept;
-        }
-        return kept;
-    }
-
-    int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
-        mTempConfig.setTo(getRequestedOverrideConfiguration());
-        final int changes = mTempConfig.updateFrom(values);
-        if (changes != 0) {
-            Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
-                    + mTempConfig + " for displayId=" + mDisplayId);
-            onRequestedOverrideConfigurationChanged(mTempConfig);
-
-            final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
-            if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
-                mAtmService.mAppWarnings.onDensityChanged();
-
-                // Post message to start process to avoid possible deadlock of calling into AMS with
-                // the ATMS lock held.
-                final Message msg = PooledLambda.obtainMessage(
-                        ActivityManagerInternal::killAllBackgroundProcessesExcept,
-                        mAtmService.mAmInternal, N,
-                        ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
-                mAtmService.mH.sendMessage(msg);
-            }
-            mWmService.mDisplayNotificationController.dispatchDisplayChanged(
-                    this, getConfiguration());
-        }
-        return changes;
-    }
-
-    @Override
-    public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        final int currRotation =
-                getRequestedOverrideConfiguration().windowConfiguration.getRotation();
-        if (currRotation != ROTATION_UNDEFINED
-                && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
-            applyRotationLocked(currRotation,
-                    overrideConfiguration.windowConfiguration.getRotation());
-        }
-        super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
-        mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
-        mAtmService.addWindowLayoutReasons(
-                ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        // update resources before cascade so that docked/pinned stacks use the correct info
-        preOnConfigurationChanged();
-        super.onConfigurationChanged(newParentConfig);
-    }
-
-    /** Checks whether the given activity is in size compatibility mode and notifies the change. */
-    void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
-        if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
-            // The callback is only interested in the foreground changes of fullscreen activity.
-            return;
-        }
-        if (!r.inSizeCompatMode()) {
-            if (mLastCompatModeActivity != null) {
-                mAtmService.getTaskChangeNotificationController()
-                        .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
-            }
-            mLastCompatModeActivity = null;
-            return;
-        }
-        if (mLastCompatModeActivity == r) {
-            return;
-        }
-        mLastCompatModeActivity = r;
-        mAtmService.getTaskChangeNotificationController()
-                .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
-    }
-
-    @Override
-    public String toString() {
-        return "ActivityDisplay={" + mDisplayId + " numStacks=" + getStackCount() + "}";
-    }
-
-    boolean isPrivate() {
-        return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
-    }
-
-    boolean isUidPresent(int uid) {
-        final PooledPredicate p = PooledLambda.obtainPredicate(
-                ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
-        final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
-        p.recycle();
-        return isUidPresent;
-    }
-
-    /**
-     * @see #mRemoved
-     */
-    boolean isRemoved() {
-        return mRemoved;
-    }
-
-    /**
-     * @see #mRemoving
-     */
-    boolean isRemoving() {
-        return mRemoving;
-    }
-
-    void remove() {
-        mRemoving = true;
-        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
-        ActivityStack lastReparentedStack = null;
-        mPreferredTopFocusableStack = null;
-
-        // Stacks could be reparented from the removed display to other display. While
-        // reparenting the last stack of the removed display, the remove display is ready to be
-        // released (no more ActivityStack). But, we cannot release it at that moment or the
-        // related WindowContainer will also be removed. So, we set display as removed after
-        // reparenting stack finished.
-        final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
-        mRootActivityContainer.mStackSupervisor.beginDeferResume();
-        try {
-            int numStacks = getStackCount();
-            // Keep the order from bottom to top.
-            for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-                final ActivityStack stack = getStackAt(stackNdx);
-                // Always finish non-standard type stacks.
-                if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
-                    stack.finishAllActivitiesImmediately();
-                } else {
-                    // If default display is in split-window mode, set windowing mode of the stack
-                    // to split-screen secondary. Otherwise, set the windowing mode to undefined by
-                    // default to let stack inherited the windowing mode from the new display.
-                    final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
-                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                            : WINDOWING_MODE_UNDEFINED;
-                    stack.reparent(toDisplay, true /* onTop */);
-                    stack.setWindowingMode(windowingMode);
-                    lastReparentedStack = stack;
-                }
-                // Stacks may be removed from this display. Ensure each stack will be processed and
-                // the loop will end.
-                stackNdx -= numStacks - getStackCount();
-                numStacks = getStackCount();
-            }
-        } finally {
-            mRootActivityContainer.mStackSupervisor.endDeferResume();
-        }
-        mRemoved = true;
-
-        // Only update focus/visibility for the last one because there may be many stacks are
-        // reparented and the intermediate states are unnecessary.
-        if (lastReparentedStack != null) {
-            lastReparentedStack.postReparent();
-        }
-        releaseSelfIfNeeded();
-
-        if (!mAllSleepTokens.isEmpty()) {
-            mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
-            mAllSleepTokens.clear();
-            mAtmService.updateSleepIfNeededLocked();
-        }
-    }
-
-    private void releaseSelfIfNeeded() {
-        if (!mRemoved) {
-            return;
-        }
-
-        final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
-        if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
-            // Release this display if an empty home stack is the only thing left.
-            // Since it is the last stack, this display will be released along with the stack
-            // removal.
-            stack.removeIfPossible();
-        } else if (getTopStack() == null) {
-            removeIfPossible();
-            mRootActivityContainer.removeChild(this);
-            mRootActivityContainer.mStackSupervisor
-                    .getKeyguardController().onDisplayRemoved(mDisplayId);
-        }
-    }
-
-    /** Update and get all UIDs that are present on the display and have access to it. */
-    IntArray getPresentUIDs() {
-        mDisplayAccessUIDs.clear();
-        final PooledConsumer c = PooledLambda.obtainConsumer(ActivityDisplay::addActivityUid,
-                PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
-        mDisplayContent.forAllActivities(c);
-        c.recycle();
-        return mDisplayAccessUIDs;
-    }
-
-    private static void addActivityUid(ActivityRecord r, IntArray uids) {
-        uids.add(r.getUid());
-    }
-
-    @VisibleForTesting
-    boolean shouldDestroyContentOnRemove() {
-        return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
-    }
-
-    boolean shouldSleep() {
-        return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
-                && (mAtmService.mRunningVoice == null);
-    }
-
-    void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
-        final ActivityRecord newFocus;
-        final IBinder token = r.appToken;
-        if (token == null) {
-            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
-                    mDisplayId);
-            newFocus = null;
-        } else {
-            newFocus = mWmService.mRoot.getActivityRecord(token);
-            if (newFocus == null) {
-                Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
-                        + ", displayId=" + mDisplayId);
-            }
-            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
-                    "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
-                            moveFocusNow, mDisplayId);
-        }
-
-        final boolean changed = setFocusedApp(newFocus);
-        if (moveFocusNow && changed) {
-            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
-                    true /*updateInputWindows*/);
-        }
-    }
-
-    /**
-     * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
-     *         already top-most.
-     */
-    ActivityStack getStackAbove(ActivityStack stack) {
-        final int stackIndex = getIndexOf(stack) + 1;
-        return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
-    }
-
-    /**
-     * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
-     * Generally used in conjunction with {@link #moveStackBehindStack}.
-     */
-    void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
-        if (stack.shouldBeVisible(null)) {
-            // Skip if the stack is already visible
-            return;
-        }
-
-        // Move the stack to the bottom to not affect the following visibility checks
-        positionStackAtBottom(stack);
-
-        // Find the next position where the stack should be placed
-        final int numStacks = getStackCount();
-        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-            final ActivityStack s = getStackAt(stackNdx);
-            if (s == stack) {
-                continue;
-            }
-            final int winMode = s.getWindowingMode();
-            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
-                    winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-            if (s.shouldBeVisible(null) && isValidWindowingMode) {
-                // Move the provided stack to behind this stack
-                positionStackAt(stack, Math.max(0, stackNdx - 1));
-                break;
-            }
-        }
-    }
-
-    /**
-     * Moves the {@param stack} behind the given {@param behindStack} if possible. If
-     * {@param behindStack} is not currently in the display, then then the stack is moved to the
-     * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
-     */
-    void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
-        if (behindStack == null || behindStack == stack) {
-            return;
-        }
-
-        // Note that positionChildAt will first remove the given stack before inserting into the
-        // list, so we need to adjust the insertion index to account for the removed index
-        // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
-        //       position internally
-        final int stackIndex = getIndexOf(stack);
-        final int behindStackIndex = getIndexOf(behindStack);
-        final int insertIndex = stackIndex <= behindStackIndex
-                ? behindStackIndex - 1 : behindStackIndex;
-        positionStackAt(stack, Math.max(0, insertIndex));
-    }
-
-    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
-        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getStackAt(stackNdx);
-            stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
-                    notifyClients);
-        }
-    }
-
-    void moveHomeStackToFront(String reason) {
-        final ActivityStack homeStack = getHomeStack();
-        if (homeStack != null) {
-            homeStack.moveToFront(reason);
-        }
-    }
-
-    /**
-     * Moves the focusable home activity to top. If there is no such activity, the home stack will
-     * still move to top.
-     */
-    void moveHomeActivityToTop(String reason) {
-        final ActivityRecord top = getHomeActivity();
-        if (top == null) {
-            moveHomeStackToFront(reason);
-            return;
-        }
-        top.moveFocusableActivityToTop(reason);
-    }
-
-    @Nullable
-    ActivityRecord getHomeActivity() {
-        return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
-    }
-
-    @Nullable
-    ActivityRecord getHomeActivityForUser(int userId) {
-        final ActivityStack homeStack = getHomeStack();
-        if (homeStack == null) {
-            return null;
-        }
-
-        final PooledPredicate p = PooledLambda.obtainPredicate(
-                ActivityDisplay::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
-                userId);
-        final ActivityRecord r = homeStack.getActivity(p);
-        p.recycle();
-        return r;
-    }
-
-    private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
-        return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
-    }
-
-    boolean isSleeping() {
-        return mSleeping;
-    }
-
-    void setIsSleeping(boolean asleep) {
-        mSleeping = asleep;
-    }
-
-    /**
-     * Adds a listener to be notified whenever the stack order in the display changes. Currently
-     * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
-     * current animation when the system state changes.
-     */
-    void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
-        if (!mStackOrderChangedCallbacks.contains(listener)) {
-            mStackOrderChangedCallbacks.add(listener);
-        }
-    }
-
-    /**
-     * Removes a previously registered stack order change listener.
-     */
-    void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
-        mStackOrderChangedCallbacks.remove(listener);
-    }
-
-    /**
-     * Notifies of a stack order change
-     * @param stack The stack which triggered the order change
-     */
-    private void onStackOrderChanged(ActivityStack stack) {
-        for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
-            mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
-        }
-    }
-
-    void setDisplayToSingleTaskInstance() {
-        final int childCount = getStackCount();
-        if (childCount > 1) {
-            throw new IllegalArgumentException("Display already has multiple stacks. display="
-                    + this);
-        }
-        if (childCount > 0) {
-            final ActivityStack stack = getStackAt(0);
-            if (stack.getChildCount() > 1) {
-                throw new IllegalArgumentException("Display stack already has multiple tasks."
-                        + " display=" + this + " stack=" + stack);
-            }
-        }
-
-        mSingleTaskInstance = true;
-    }
-
-    /** Returns true if the display can only contain one task */
-    boolean isSingleTaskInstance() {
-        return mSingleTaskInstance;
-    }
-
-    @VisibleForTesting
-    void removeAllTasks() {
-        mDisplayContent.forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); });
-    }
-
-    public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getStackCount()
-                + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
-        final String myPrefix = prefix + " ";
-        ActivityStack stack = getHomeStack();
-        if (stack != null) {
-            pw.println(myPrefix + "mHomeStack=" + stack);
-        }
-        stack = getRecentsStack();
-        if (stack != null) {
-            pw.println(myPrefix + "mRecentsStack=" + stack);
-        }
-        stack = getPinnedStack();
-        if (stack != null) {
-            pw.println(myPrefix + "mPinnedStack=" + stack);
-        }
-        stack = getSplitScreenPrimaryStack();
-        if (stack != null) {
-            pw.println(myPrefix + "mSplitScreenPrimaryStack=" + stack);
-        }
-        if (mPreferredTopFocusableStack != null) {
-            pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
-        }
-        if (mLastFocusedStack != null) {
-            pw.println(myPrefix + "mLastFocusedStack=" + mLastFocusedStack);
-        }
-    }
-
-    public void dumpStacks(PrintWriter pw) {
-        for (int i = getStackCount() - 1; i >= 0; --i) {
-            pw.print(getStackAt(i).mStackId);
-            if (i > 0) {
-                pw.print(",");
-            }
-        }
-    }
-
-    public void dumpDebug(ProtoOutputStream proto, long fieldId,
-            @WindowTraceLogLevel int logLevel) {
-        final long token = proto.start(fieldId);
-        dumpDebugInner(proto, DISPLAY, logLevel);
-        proto.write(ID, mDisplayId);
-        proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
-        final ActivityStack focusedStack = getFocusedStack();
-        if (focusedStack != null) {
-            proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
-            final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
-            if (focusedActivity != null) {
-                focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
-            }
-        } else {
-            proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
-        }
-        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getStackAt(stackNdx);
-            stack.dumpDebug(proto, STACKS, logLevel);
-        }
-        proto.end(token);
-    }
-
-    /**
-     * Callback for when the order of the stacks in the display changes.
-     */
-    interface OnStackOrderChangedListener {
-        void onStackOrderChanged(ActivityStack stack);
-    }
-}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 20d1d1c..c8357e29 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -190,6 +190,8 @@
         final int mTransitionType;
         /** Whether the process was already running when the transition started. */
         final boolean mProcessRunning;
+        /** whether the process of the launching activity didn't have any active activity. */
+        final boolean mProcessSwitch;
         /** The activities that should be drawn. */
         final LinkedList<ActivityRecord> mPendingDrawActivities = new LinkedList<>();
         /** The latest activity to have been launched. */
@@ -218,7 +220,8 @@
         /** @return Non-null if there will be a window drawn event for the launch. */
         @Nullable
         static TransitionInfo create(@NonNull ActivityRecord r,
-                @NonNull LaunchingState launchingState, boolean processRunning, int startResult) {
+                @NonNull LaunchingState launchingState, boolean processRunning,
+                boolean processSwitch, int startResult) {
             int transitionType = INVALID_TRANSITION_TYPE;
             if (processRunning) {
                 if (startResult == START_SUCCESS) {
@@ -235,16 +238,18 @@
                 // That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
                 return null;
             }
-            return new TransitionInfo(r, launchingState, transitionType, processRunning);
+            return new TransitionInfo(r, launchingState, transitionType, processRunning,
+                    processSwitch);
         }
 
         /** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
         private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
-                boolean processRunning) {
+                boolean processRunning, boolean processSwitch) {
             mLaunchingState = launchingState;
             mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
             mTransitionType = transitionType;
             mProcessRunning = processRunning;
+            mProcessSwitch = processSwitch;
             mCurrentTransitionDeviceUptime =
                     (int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
             setLatestLaunchedActivity(r);
@@ -282,6 +287,14 @@
             return mPendingDrawActivities.isEmpty();
         }
 
+        /**
+         * @return {@code true} if the transition info should be sent to MetricsLogger, StatsLog, or
+         *         LaunchObserver.
+         */
+        boolean isInterestingToLoggerAndObserver() {
+            return mProcessSwitch;
+        }
+
         int calculateCurrentDelay() {
             return calculateDelay(SystemClock.elapsedRealtimeNanos());
         }
@@ -540,13 +553,8 @@
             return;
         }
 
-        if (!processSwitch) {
-            abort(info, "not a process switch");
-            return;
-        }
-
         final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
-                processRunning, resultCode);
+                processRunning, processSwitch, resultCode);
         if (newInfo == null) {
             abort(info, "unrecognized launch");
             return;
@@ -557,7 +565,12 @@
         mTransitionInfoList.add(newInfo);
         mLastTransitionInfo.put(launchedActivity, newInfo);
         startLaunchTrace(newInfo);
-        launchObserverNotifyActivityLaunched(newInfo);
+        if (newInfo.isInterestingToLoggerAndObserver()) {
+            launchObserverNotifyActivityLaunched(newInfo);
+        } else {
+            // As abort for no process switch.
+            launchObserverNotifyIntentFailed();
+        }
     }
 
     /**
@@ -733,7 +746,9 @@
             launchObserverNotifyActivityLaunchCancelled(info);
         } else {
             logAppTransitionFinished(info);
-            launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+            if (info.isInterestingToLoggerAndObserver()) {
+                launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+            }
         }
         info.mPendingDrawActivities.clear();
         mTransitionInfoList.remove(info);
@@ -768,8 +783,11 @@
         // Take a snapshot of the transition info before sending it to the handler for logging.
         // This will avoid any races with other operations that modify the ActivityRecord.
         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
-        BackgroundThread.getHandler().post(() -> logAppTransition(
-                info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs, infoSnapshot));
+        if (info.isInterestingToLoggerAndObserver()) {
+            BackgroundThread.getHandler().post(() -> logAppTransition(
+                    info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs,
+                    infoSnapshot));
+        }
         BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
         if (info.mPendingFullyDrawn != null) {
             info.mPendingFullyDrawn.run();
@@ -905,6 +923,18 @@
             return null;
         }
 
+        final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
+        final long startupTimeMs = info.mPendingFullyDrawn != null
+                ? info.mWindowsDrawnDelayMs
+                : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
+        final TransitionInfoSnapshot infoSnapshot =
+                new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
+        BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
+
+        if (!info.isInterestingToLoggerAndObserver()) {
+            return infoSnapshot;
+        }
+
         // Record the handling of the reportFullyDrawn callback in the trace system. This is not
         // actually used to trace this function, but instead the logical task that this function
         // fullfils (handling reportFullyDrawn() callbacks).
@@ -914,10 +944,6 @@
         final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
         builder.setPackageName(r.packageName);
         builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
-        final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
-        final long startupTimeMs = info.mPendingFullyDrawn != null
-                ? info.mWindowsDrawnDelayMs
-                : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
         builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
         builder.setType(restoredFromBundle
                 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
@@ -940,10 +966,6 @@
         // the trace slice to have a noticable duration.
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
-        final TransitionInfoSnapshot infoSnapshot =
-                new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
-        BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
-
         // Notify reportFullyDrawn event.
         launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
 
@@ -1069,7 +1091,8 @@
             return;
         }
         info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
-        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
+                (int) info.mTransitionStartTimeNs /* cookie */);
     }
 
     /** Stops trace for the launch is completed or cancelled. */
@@ -1078,7 +1101,8 @@
         if (info.mLaunchTraceName == null) {
             return;
         }
-        Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
+                (int) info.mTransitionStartTimeNs /* cookie */);
         info.mLaunchTraceName = null;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bc2fa4e..6de9dbd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1640,6 +1640,17 @@
                 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
 
         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
+            if (isActivityTypeHome()) {
+                // The snapshot of home is only used once because it won't be updated while screen
+                // is on (see {@link TaskSnapshotController#screenTurningOff}).
+                mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId);
+                // TODO(b/9684093): Use more general condition to specify the case.
+                if (mDisplayContent.mAppTransition
+                        .getAppTransition() != WindowManager.TRANSIT_KEYGUARD_GOING_AWAY) {
+                    // Only use snapshot of home as starting window when unlocking.
+                    return false;
+                }
+            }
             return createSnapshot(snapshot);
         }
 
@@ -1991,7 +2002,7 @@
         return getActivityStack() != null ? getActivityStack().mStackId : INVALID_STACK_ID;
     }
 
-    ActivityDisplay getDisplay() {
+    DisplayContent getDisplay() {
         final ActivityStack stack = getActivityStack();
         return stack != null ? stack.getDisplay() : null;
     }
@@ -2148,7 +2159,7 @@
         boolean isKeyguardLocked = mAtmService.isKeyguardLocked();
         boolean isCurrentAppLocked =
                 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         boolean hasPinnedStack = display != null && display.hasPinnedStack();
         // Don't return early if !isNotLocked, since we want to throw an exception if the activity
         // is in an incorrect state
@@ -2212,11 +2223,15 @@
         return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
     }
 
+    boolean windowsAreFocusable() {
+        return windowsAreFocusable(false /* fromUserTouch */);
+    }
+
     // TODO: Does this really need to be different from isAlwaysFocusable()? For the activity side
     // focusable means resumeable. I guess with that in mind maybe we should rename the other
     // method to isResumeable() or something like that.
-    boolean windowsAreFocusable() {
-        if (mTargetSdk < Build.VERSION_CODES.Q) {
+    boolean windowsAreFocusable(boolean fromUserTouch) {
+        if (!fromUserTouch && mTargetSdk < Build.VERSION_CODES.Q) {
             final int pid = getPid();
             final ActivityRecord topFocusedAppOfMyProcess =
                     mWmService.mRoot.mTopFocusedAppByProcess.get(pid);
@@ -2230,7 +2245,12 @@
                 && getDisplay() != null;
     }
 
-    /** Move activity with its stack to front and make the stack focused. */
+    /**
+     * Move activity with its stack to front and make the stack focused.
+     * @param reason the reason to move to top
+     * @return {@code true} if the stack is focusable and has been moved to top or the activity
+     *         is not yet resumed while the stack is already on top, {@code false} otherwise.
+     */
     boolean moveFocusableActivityToTop(String reason) {
         if (!isFocusable()) {
             if (DEBUG_FOCUS) {
@@ -2251,7 +2271,7 @@
             if (DEBUG_FOCUS) {
                 Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
             }
-            return false;
+            return !isState(RESUMED);
         }
 
         if (DEBUG_FOCUS) {
@@ -2408,7 +2428,7 @@
                     stack.adjustFocusToNextFocusableStack("finish-top");
                 } else {
                     // Only move the next stack to top in its display.
-                    final ActivityDisplay display = stack.getDisplay();
+                    final DisplayContent display = stack.getDisplay();
                     next = display.topRunningActivity();
                     if (next != null) {
                         display.positionStackAtTop(next.getActivityStack(),
@@ -2582,9 +2602,9 @@
         mStackSupervisor.mGoingToSleepActivities.remove(this);
 
         final ActivityStack stack = getActivityStack();
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         // TODO(b/137329632): Exclude current activity when looking for the next one with
-        //  ActivityDisplay#topRunningActivity().
+        // DisplayContent#topRunningActivity().
         final ActivityRecord next = display.topRunningActivity();
         final boolean isLastStackOverEmptyHome =
                 next == null && stack.isFocusedStackOnDisplay() && display.getHomeStack() != null;
@@ -4651,7 +4671,7 @@
         }
         r.setSavedState(null /* savedState */);
 
-        final ActivityDisplay display = r.getDisplay();
+        final DisplayContent display = r.getDisplay();
         if (display != null) {
             display.handleActivitySizeCompatModeIfNeeded(r);
         }
@@ -6248,7 +6268,7 @@
         }
 
         // The role of CompatDisplayInsets is like the override bounds.
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         if (display != null) {
             mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent,
                     getWindowConfiguration().getBounds(),
@@ -6518,7 +6538,7 @@
             onMergedOverrideConfigurationChanged();
         }
 
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         if (display == null) {
             return;
         }
@@ -7267,7 +7287,7 @@
      * otherwise.
      */
     boolean isResumedActivityOnDisplay() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         return display != null && this == display.getResumedActivity();
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index eb1f638..677d2a1 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -131,8 +131,6 @@
 import android.app.IActivityController;
 import android.app.RemoteAction;
 import android.app.ResultInfo;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
 import android.app.servertransaction.ActivityResultItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.NewIntentItem;
@@ -144,7 +142,6 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
@@ -154,9 +151,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
-import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
@@ -732,7 +727,7 @@
         }
     }
 
-    ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
+    ActivityStack(DisplayContent display, int stackId, ActivityStackSupervisor supervisor,
             int windowingMode, int activityType, boolean onTop) {
         super(supervisor.mService.mWindowManager);
         mStackId = stackId;
@@ -816,7 +811,7 @@
             }
         }
 
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         if (display == null ) {
             return;
         }
@@ -946,7 +941,7 @@
             boolean creating) {
         final int currentMode = getWindowingMode();
         final int currentOverrideMode = getRequestedOverrideWindowingMode();
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         final Task topTask = getTopMostTask();
         final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
         int windowingMode = preferredWindowingMode;
@@ -1116,8 +1111,8 @@
                 !PRESERVE_WINDOWS);
     }
 
-    ActivityDisplay getDisplay() {
-        return mRootActivityContainer.getActivityDisplay(mDisplayId);
+    DisplayContent getDisplay() {
+        return getDisplayContent();
     }
 
     /**
@@ -1250,7 +1245,7 @@
 
     /** @return true if the stack can only contain one task */
     boolean isSingleTaskInstance() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         return display != null && display.isSingleTaskInstance();
     }
 
@@ -1291,7 +1286,7 @@
             return;
         }
 
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
 
         if (inSplitScreenSecondaryWindowingMode()) {
             // If the stack is in split-screen seconardy mode, we need to make sure we move the
@@ -1358,7 +1353,7 @@
 
     @Override
     public boolean isAttached() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         return display != null && !display.isRemoved();
     }
 
@@ -1777,7 +1772,7 @@
     }
 
     boolean isTopStackOnDisplay() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         return display != null && display.isTopStack(this);
     }
 
@@ -1786,7 +1781,7 @@
      * otherwise.
      */
     boolean isFocusedStackOnDisplay() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         return display != null && this == display.getFocusedStack();
     }
 
@@ -1815,7 +1810,7 @@
             return STACK_VISIBILITY_INVISIBLE;
         }
 
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         boolean gotSplitScreenStack = false;
         boolean gotOpaqueSplitScreenPrimary = false;
         boolean gotOpaqueSplitScreenSecondary = false;
@@ -2049,13 +2044,13 @@
      * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
      */
     boolean canShowWithInsecureKeyguard() {
-        final ActivityDisplay activityDisplay = getDisplay();
-        if (activityDisplay == null) {
+        final DisplayContent displayContent = getDisplay();
+        if (displayContent == null) {
             throw new IllegalStateException("Stack is not attached to any display, stackId="
                     + mStackId);
         }
 
-        final int flags = activityDisplay.mDisplay.getFlags();
+        final int flags = displayContent.mDisplay.getFlags();
         return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0;
     }
 
@@ -2224,7 +2219,7 @@
         }
 
         next.delayedResume = false;
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
 
         // If the top activity is the resumed one, nothing to do.
         if (mResumedActivity == next && next.isState(RESUMED)
@@ -2966,7 +2961,7 @@
 
     /** @return true if the stack behind this one is a standard activity type. */
     private boolean inFrontOfStandardStack() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         if (display == null) {
             return false;
         }
@@ -3665,7 +3660,7 @@
             return;
         }
 
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + child);
 
@@ -3693,7 +3688,7 @@
     }
 
     void moveHomeStackToFrontIfNeeded(
-            boolean wasTopFocusedStack, ActivityDisplay display, String reason) {
+            boolean wasTopFocusedStack, DisplayContent display, String reason) {
         if (!hasChild() && wasTopFocusedStack) {
             // We only need to adjust focused stack if this stack is in focus and we are not in the
             // process of moving the task to the top of the stack that will be focused.
@@ -3790,11 +3785,11 @@
             return;
         }
         super.setAlwaysOnTop(alwaysOnTop);
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
         // positionChildAtTop() must be called even when always on top gets turned off because we
         // need to make sure that the stack is moved from among always on top windows to below other
         // always on top windows. Since the position the stack should be inserted into is calculated
-        // properly in {@link ActivityDisplay#getTopInsertPosition()} in both cases, we can just
+        // properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just
         // request that the stack is put at top here.
         display.positionStackAtTop(this, false /* includingParents */);
     }
@@ -4352,11 +4347,10 @@
     @Override
     protected void onParentChanged(
             ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        // TODO(display-merge): Remove cast
-        final ActivityDisplay display = newParent != null
-                ? (ActivityDisplay) ((WindowContainer) newParent).getDisplayContent() : null;
-        final ActivityDisplay oldDisplay = oldParent != null
-                ? (ActivityDisplay) ((WindowContainer) oldParent).getDisplayContent() : null;
+        final DisplayContent display = newParent != null
+                ? ((WindowContainer) newParent).getDisplayContent() : null;
+        final DisplayContent oldDisplay = oldParent != null
+                ? ((WindowContainer) oldParent).getDisplayContent() : null;
 
         mDisplayId = (display != null) ? display.mDisplayId : INVALID_DISPLAY;
         mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
@@ -5408,7 +5402,7 @@
     }
 
     boolean shouldSleepActivities() {
-        final ActivityDisplay display = getDisplay();
+        final DisplayContent display = getDisplay();
 
         // Do not sleep activities in this stack if we're marked as focused and the keyguard
         // is in the process of going away.
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 8c5fd8c..43dce73 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -401,12 +401,12 @@
     private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
             new MoveTaskToFullscreenHelper();
     private class MoveTaskToFullscreenHelper {
-        private ActivityDisplay mToDisplay;
+        private DisplayContent mToDisplay;
         private boolean mOnTop;
         private Task mTopTask;
         private boolean mSchedulePictureInPictureModeChange;
 
-        void process(ActivityStack fromStack, ActivityDisplay toDisplay, boolean onTop,
+        void process(ActivityStack fromStack, DisplayContent toDisplay, boolean onTop,
                 boolean schedulePictureInPictureModeChange) {
             mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
             mToDisplay = toDisplay;
@@ -1122,9 +1122,9 @@
             return true;
         }
 
-        final ActivityDisplay activityDisplay =
-                mRootActivityContainer.getActivityDisplayOrCreate(launchDisplayId);
-        if (activityDisplay == null || activityDisplay.isRemoved()) {
+        final DisplayContent displayContent =
+                mRootActivityContainer.getDisplayContentOrCreate(launchDisplayId);
+        if (displayContent == null || displayContent.isRemoved()) {
             Slog.w(TAG, "Launch on display check: display not found");
             return false;
         }
@@ -1140,10 +1140,10 @@
         }
 
         // Check if caller is already present on display
-        final boolean uidPresentOnDisplay = activityDisplay.isUidPresent(callingUid);
+        final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);
 
-        final int displayOwnerUid = activityDisplay.mDisplay.getOwnerUid();
-        if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
+        final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
+        if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
                 && displayOwnerUid != aInfo.applicationInfo.uid) {
             // Limit launching on virtual displays, because their contents can be read from Surface
             // by apps that created them.
@@ -1161,7 +1161,7 @@
             }
         }
 
-        if (!activityDisplay.isPrivate()) {
+        if (!displayContent.isPrivate()) {
             // Anyone can launch on a public display.
             if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
                     + " allow launch on public display");
@@ -1482,7 +1482,7 @@
                 currentStack, forceNonResizeable);
     }
 
-    private void moveHomeStackToFrontIfNeeded(int flags, ActivityDisplay display, String reason) {
+    private void moveHomeStackToFrontIfNeeded(int flags, DisplayContent display, String reason) {
         final ActivityStack focusedStack = display.getFocusedStack();
 
         if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
@@ -1542,8 +1542,8 @@
         mService.deferWindowLayout();
         try {
             final int windowingMode = fromStack.getWindowingMode();
-            final ActivityDisplay toDisplay =
-                    mRootActivityContainer.getActivityDisplay(toDisplayId);
+            final DisplayContent toDisplay =
+                    mRootActivityContainer.getDisplayContent(toDisplayId);
 
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 // We are moving all tasks from the docked stack to the fullscreen stack,
@@ -1668,7 +1668,7 @@
                 // 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 ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+                final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
                 final Rect otherTaskRect = new Rect();
                 for (int i = display.getStackCount() - 1; i >= 0; --i) {
                     final ActivityStack current = display.getStackAt(i);
@@ -1934,7 +1934,7 @@
      * Returns the reparent target stack, creating the stack if necessary.  This call also enforces
      * the various checks on tasks that are going to be reparented from one stack to another.
      */
-    // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
+    // TODO: Look into changing users to this method to DisplayContent.resolveWindowingMode()
     ActivityStack getReparentTargetStack(Task task, ActivityStack stack, boolean toTop) {
         final ActivityStack prevStack = task.getStack();
         final int stackId = stack.mStackId;
@@ -2426,8 +2426,8 @@
                 throw new IllegalStateException("Task resolved to incompatible display");
             }
 
-            final ActivityDisplay preferredDisplay =
-                    mRootActivityContainer.getActivityDisplay(preferredDisplayId);
+            final DisplayContent preferredDisplay =
+                    mRootActivityContainer.getDisplayContent(preferredDisplayId);
 
             final boolean singleTaskInstance = preferredDisplay != null
                     && preferredDisplay.isSingleTaskInstance();
@@ -2818,7 +2818,7 @@
                 // call this at the end to make sure that tasks exists on the window manager side.
                 setResizingDuringAnimation(task);
 
-                final ActivityDisplay display = task.getStack().getDisplay();
+                final DisplayContent display = task.getStack().getDisplay();
                 final ActivityStack topSecondaryStack =
                         display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
                 if (topSecondaryStack.isActivityTypeHome()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 695f58c..4c165df 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -43,6 +43,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.RemoteAnimationAdapter;
 
@@ -180,8 +181,8 @@
         }
         options.setLaunchDisplayId(displayId);
 
-        final ActivityDisplay display =
-                mService.mRootActivityContainer.getActivityDisplay(displayId);
+        final DisplayContent display =
+                mService.mRootActivityContainer.getDisplayContent(displayId);
         // The home activity will be started later, defer resuming to avoid unneccerary operations
         // (e.g. start home recursively) when creating home stack.
         mSupervisor.beginDeferResume();
@@ -385,6 +386,7 @@
         } else {
             callingPid = callingUid = -1;
         }
+        final SparseArray<String> startingUidPkgs = new SparseArray<>();
         final long origId = Binder.clearCallingIdentity();
         try {
             intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
@@ -411,9 +413,14 @@
                                 callingUid, realCallingUid, UserHandle.USER_NULL));
                 aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
 
-                if (aInfo != null && (aInfo.applicationInfo.privateFlags
-                        & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
-                    throw new IllegalArgumentException("FLAG_CANT_SAVE_STATE not supported here");
+                if (aInfo != null) {
+                    if ((aInfo.applicationInfo.privateFlags
+                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+                        throw new IllegalArgumentException(
+                                "FLAG_CANT_SAVE_STATE not supported here");
+                    }
+                    startingUidPkgs.put(aInfo.applicationInfo.uid,
+                            aInfo.applicationInfo.packageName);
                 }
 
                 final boolean top = i == intents.length - 1;
@@ -439,6 +446,16 @@
                         .setOriginatingPendingIntent(originatingPendingIntent)
                         .setAllowBackgroundActivityStart(allowBackgroundActivityStart);
             }
+            // Log if the activities to be started have different uids.
+            if (startingUidPkgs.size() > 1) {
+                final StringBuilder sb = new StringBuilder("startActivities: different apps [");
+                final int size = startingUidPkgs.size();
+                for (int i = 0; i < size; i++) {
+                    sb.append(startingUidPkgs.valueAt(i)).append(i == size - 1 ? "]" : ", ");
+                }
+                sb.append(" from ").append(callingPackage);
+                Slog.wtf(TAG, sb.toString());
+            }
 
             final ActivityRecord[] outActivity = new ActivityRecord[1];
             // Lock the loop to ensure the activities launched in a sequence.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46c4d87..f0bc412 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2038,7 +2038,7 @@
     }
 
     @Override
-    public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
+    public int getDisplayId(IBinder activityToken) throws RemoteException {
         synchronized (mGlobalLock) {
             final ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
             if (stack != null && stack.mDisplayId != INVALID_DISPLAY) {
@@ -4572,6 +4572,17 @@
         }
     }
 
+    @Override
+    public void invalidateHomeTaskSnapshot(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null || !r.isActivityTypeHome()) {
+                return;
+            }
+            mWindowManager.mTaskSnapshotController.removeSnapshotCache(r.getTask().mTaskId);
+        }
+    }
+
     /** Return the user id of the last resumed activity. */
     @Override
     public @UserIdInt
@@ -4691,7 +4702,7 @@
                 "registerRemoteAnimations");
         definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
         synchronized (mGlobalLock) {
-            final ActivityDisplay display = mRootActivityContainer.getActivityDisplay(displayId);
+            final DisplayContent display = mRootActivityContainer.getDisplayContent(displayId);
             if (display == null) {
                 Slog.e(TAG, "Couldn't find display with id: " + displayId);
                 return;
@@ -4899,8 +4910,8 @@
                 "setDisplayToSingleTaskInstance");
         final long origId = Binder.clearCallingIdentity();
         try {
-            final ActivityDisplay display =
-                    mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+            final DisplayContent display =
+                    mRootActivityContainer.getDisplayContentOrCreate(displayId);
             if (display != null) {
                 display.setDisplayToSingleTaskInstance();
             }
@@ -5198,8 +5209,8 @@
     int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
             boolean persistent, int userId, boolean deferResume) {
 
-        final ActivityDisplay defaultDisplay =
-                mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+        final DisplayContent defaultDisplay =
+                mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY);
 
         mTempConfig.setTo(getGlobalConfiguration());
         final int changes = mTempConfig.updateFrom(values);
@@ -6205,12 +6216,12 @@
 
                 // We might change the visibilities here, so prepare an empty app transition which
                 // might be overridden later if we actually change visibilities.
-                final ActivityDisplay activityDisplay =
-                        mRootActivityContainer.getActivityDisplay(displayId);
-                if (activityDisplay == null) {
+                final DisplayContent displayContent =
+                        mRootActivityContainer.getDisplayContent(displayId);
+                if (displayContent == null) {
                     return;
                 }
-                final DisplayContent dc = activityDisplay.mDisplayContent;
+                final DisplayContent dc = displayContent.mDisplayContent;
                 final boolean wasTransitionSet =
                         dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
                 if (!wasTransitionSet) {
@@ -6557,9 +6568,9 @@
                 return;
             }
             synchronized (mGlobalLock) {
-                final ActivityDisplay activityDisplay =
-                        mRootActivityContainer.getActivityDisplay(displayId);
-                if (activityDisplay == null) {
+                final DisplayContent displayContent =
+                        mRootActivityContainer.getDisplayContent(displayId);
+                if (displayContent == null) {
                     // Call might come when display is not yet added or has been removed.
                     if (DEBUG_CONFIGURATION) {
                         Slog.w(TAG, "Trying to update display configuration for non-existing "
@@ -6576,7 +6587,7 @@
                     return;
                 }
                 process.mIsImeProcess = true;
-                process.registerDisplayConfigurationListenerLocked(activityDisplay);
+                process.registerDisplayConfigurationListenerLocked(displayContent);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index bd0ea3d..dd3365c 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -384,7 +384,6 @@
      *  When you call this function, make sure that the following functions are called as well to
      *  keep proper z-order.
      *  - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
-     *  - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)};
      * */
     public void setAlwaysOnTop(boolean alwaysOnTop) {
         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aa0e973..e3ea2c5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,24 +16,33 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 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;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 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.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Build.VERSION_CODES.N;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
 import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
@@ -75,10 +84,20 @@
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
 
+import static com.android.server.am.ActivityDisplayProto.DISPLAY;
+import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
+import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
 import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
@@ -105,6 +124,7 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.RootActivityContainer.TAG_STATES;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -124,6 +144,7 @@
 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;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -141,6 +162,11 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -158,15 +184,19 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
+import android.util.IntArray;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -174,6 +204,7 @@
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.ISystemGestureExclusionListener;
+import android.view.IWindow;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputWindowHandle;
@@ -196,6 +227,7 @@
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
@@ -223,6 +255,7 @@
 class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
         implements WindowManagerPolicy.DisplayContentInfo {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
 
     /** The default scaling mode that scales content automatically. */
     static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -239,7 +272,7 @@
     ActivityTaskManagerService mAtmService;
 
     /** Unique identifier of this display. */
-    private final int mDisplayId;
+    final int mDisplayId;
 
     /**
      * Most surfaces will be a child of this window. There are some special layers and windows
@@ -328,8 +361,8 @@
      * @see WindowManagerService#setForcedDisplayScalingMode(int, int)
      */
     boolean mDisplayScalingDisabled;
+    final Display mDisplay;
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
-    private final Display mDisplay;
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     private final DisplayPolicy mDisplayPolicy;
     private final DisplayRotation mDisplayRotation;
@@ -563,6 +596,74 @@
     /** Corner radius that windows should have in order to match the display. */
     private final float mWindowCornerRadius;
 
+    private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+
+    /**
+     * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
+     */
+    private static int sNextFreeStackId = 0;
+
+    private RootActivityContainer mRootActivityContainer;
+
+    /**
+     * All of the stacks on this display. Order matters, topmost stack is in front of all other
+     * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
+     * changing the list should also call {@link #onStackOrderChanged()}.
+     */
+    private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
+
+    /** Array of all UIDs that are present on the display. */
+    private IntArray mDisplayAccessUIDs = new IntArray();
+
+    /** All tokens used to put activities on this stack to sleep (including mOffToken) */
+    final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
+    /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
+    ActivityTaskManagerInternal.SleepToken mOffToken;
+
+    private boolean mSleeping;
+
+    /** We started the process of removing the display from the system. */
+    private boolean mRemoving;
+
+    /**
+     * The display is removed from the system and we are just waiting for all activities on it to be
+     * finished before removing this object.
+     */
+    private boolean mRemoved;
+
+    /** The display can only contain one task. */
+    private boolean mSingleTaskInstance;
+
+    /**
+     * Non-null if the last size compatibility mode activity is using non-native screen
+     * configuration. The activity is not able to put in multi-window mode, so it exists only one
+     * per display.
+     */
+    private ActivityRecord mLastCompatModeActivity;
+
+    /**
+     * A focusable stack that is purposely to be positioned at the top. Although the stack may not
+     * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
+     * target stack properly when there are other focusable always-on-top stacks.
+     */
+    private ActivityStack mPreferredTopFocusableStack;
+
+    /**
+     * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
+     * stack has been resumed. If stacks are changing position this will hold the old stack until
+     * the new stack becomes resumed after which it will be set to current focused stack.
+     */
+    private ActivityStack mLastFocusedStack;
+
+    // Used in updating the display size
+    private Point mTmpDisplaySize = new Point();
+
+    // Used in updating override configurations
+    private final Configuration mTempConfig = new Configuration();
+
+    private final RootActivityContainer.FindTaskResult
+            mTmpFindTaskResult = new RootActivityContainer.FindTaskResult();
+
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
         final ActivityRecord activity = w.mActivityRecord;
@@ -842,17 +943,18 @@
      * Create new {@link DisplayContent} instance, add itself to the root window container and
      * initialize direct children.
      * @param display May not be null.
-     * @param service You know.
-     * @param activityDisplay The ActivityDisplay for the display container.
+     * @param root {@link RootActivityContainer}
      */
-    DisplayContent(Display display, WindowManagerService service) {
-        super(service);
-        if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
+    DisplayContent(Display display, RootActivityContainer root) {
+        super(root.mWindowManager);
+        if (mWmService.mRoot.getDisplayContent(display.getDisplayId()) != null) {
             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
-                    + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
+                    + " already exists="
+                    + mWmService.mRoot.getDisplayContent(display.getDisplayId())
                     + " new=" + display);
         }
 
+        mRootActivityContainer = root;
         mAtmService = mWmService.mAtmService;
         mDisplay = display;
         mDisplayId = display.getDisplayId();
@@ -866,13 +968,13 @@
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
         initializeDisplayBaseInfo();
 
-        mAppTransition = new AppTransition(service.mContext, service, this);
-        mAppTransition.registerListenerLocked(service.mActivityManagerAppTransitionNotifier);
-        mAppTransitionController = new AppTransitionController(service, this);
-        mUnknownAppVisibilityController = new UnknownAppVisibilityController(service, this);
+        mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
+        mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
+        mAppTransitionController = new AppTransitionController(mWmService, this);
+        mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
 
         AnimationHandler animationHandler = new AnimationHandler();
-        mBoundsAnimationController = new BoundsAnimationController(service.mContext,
+        mBoundsAnimationController = new BoundsAnimationController(mWmService.mContext,
                 mAppTransition, AnimationThread.getHandler(), animationHandler);
 
         final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
@@ -890,9 +992,9 @@
                     mWmService.mAtmService.getRecentTasks().getInputListener());
         }
 
-        mDisplayPolicy = new DisplayPolicy(service, this);
-        mDisplayRotation = new DisplayRotation(service, this);
-        mCloseToSquareMaxAspectRatio = service.mContext.getResources().getFloat(
+        mDisplayPolicy = new DisplayPolicy(mWmService, this);
+        mDisplayRotation = new DisplayRotation(mWmService, this);
+        mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
                 com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
         if (isDefaultDisplay) {
             // The policy may be invoked right after here, so it requires the necessary default
@@ -906,8 +1008,8 @@
             mDisplayPolicy.systemReady();
         }
         mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
-        mDividerControllerLocked = new DockedStackDividerController(service, this);
-        mPinnedStackControllerLocked = new PinnedStackController(service, this);
+        mDividerControllerLocked = new DockedStackDividerController(mWmService, this);
+        mPinnedStackControllerLocked = new PinnedStackController(mWmService, this);
 
         final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
                 .setOpaque(true)
@@ -937,9 +1039,23 @@
         mDisplayReady = true;
 
         mWmService.mAnimator.addDisplayLocked(mDisplayId);
-        mInputMonitor = new InputMonitor(service, mDisplayId);
+        mInputMonitor = new InputMonitor(mWmService, mDisplayId);
         mInsetsStateController = new InsetsStateController(this);
         mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this);
+
+        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
+
+        mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+        if (mWmService.mDisplayManagerInternal != null) {
+            mWmService.mDisplayManagerInternal
+                    .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo());
+            configureDisplayPolicy();
+        }
+
+        reconfigureDisplayLocked();
+        onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
+        mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
     }
 
     boolean isReady() {
@@ -1017,6 +1133,37 @@
         return token;
     }
 
+    SurfaceControl addShellRoot(@NonNull IWindow client, int windowType) {
+        ShellRoot root = mShellRoots.get(windowType);
+        if (root != null) {
+            if (root.getClient() == client) {
+                return root.getSurfaceControl();
+            }
+            root.clear();
+            mShellRoots.remove(windowType);
+        }
+        root = new ShellRoot(client, this, windowType);
+        SurfaceControl rootLeash = root.getSurfaceControl();
+        if (rootLeash == null) {
+            // Root didn't finish initializing, so don't add it.
+            root.clear();
+            return null;
+        }
+        mShellRoots.put(windowType, root);
+        SurfaceControl out = new SurfaceControl();
+        out.copyFrom(rootLeash);
+        return out;
+    }
+
+    void removeShellRoot(int windowType) {
+        ShellRoot root = mShellRoots.get(windowType);
+        if (root == null) {
+            return;
+        }
+        root.clear();
+        mShellRoots.remove(windowType);
+    }
+
     /** Changes the display the input window token is housed on to this one. */
     void reParentWindowToken(WindowToken token) {
         final DisplayContent prevDc = token.getDisplayContent();
@@ -1154,9 +1301,7 @@
         if (mDisplayRotation.isWaitingForRemoteRotation()) {
             return;
         }
-        // TODO(display-merge): Remove cast
-        final boolean configUpdated =
-                ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked();
+        final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
         if (configUpdated) {
             return;
         }
@@ -1187,9 +1332,8 @@
 
         if (handled && requestingContainer instanceof ActivityRecord) {
             final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
-            // TODO(display-merge): Remove cast
-            final boolean kept = ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked(
-                    config, activityRecord, false /* deferResume */, null /* result */);
+            final boolean kept = updateDisplayOverrideConfigurationLocked(config, activityRecord,
+                    false /* deferResume */, null /* result */);
             activityRecord.frozenBeforeDestroy = true;
             if (!kept) {
                 mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
@@ -1197,9 +1341,8 @@
         } else {
             // We have a new configuration to push so we need to update ATMS for now.
             // TODO: Clean up display configuration push between ATMS and WMS after unification.
-            // TODO(display-merge): Remove cast
-            ((ActivityDisplay) this.mDisplayContent).updateDisplayOverrideConfigurationLocked(
-                    config, null /* starting */, false /* deferResume */, null);
+            updateDisplayOverrideConfigurationLocked(config, null /* starting */,
+                    false /* deferResume */, null);
         }
         return handled;
     }
@@ -1880,15 +2023,9 @@
     }
 
     @Override
-    public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        mCurrentOverrideConfigurationChanges =
-                getRequestedOverrideConfiguration().diff(overrideConfiguration);
-        super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
-        mCurrentOverrideConfigurationChanges = 0;
-    }
-
-    @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
+        // update resources before cascade so that docked/pinned stacks use the correct info
+        preOnConfigurationChanged();
         final int lastOrientation = getConfiguration().orientation;
         super.onConfigurationChanged(newParentConfig);
         if (mDisplayPolicy != null) {
@@ -1912,8 +2049,7 @@
     /**
      * Updates the resources used by docked/pinned controllers. This needs to be called at the
      * beginning of a configuration update cascade since the metrics from these resources are used
-     * for bounds calculations. Since ActivityDisplay initiates the configuration update, this
-     * should be called from there instead of DisplayContent's onConfigurationChanged.
+     * for bounds calculations.
      */
     void preOnConfigurationChanged() {
         final DockedStackDividerController dividerController = getDockedDividerController();
@@ -2395,9 +2531,7 @@
             setRotationAnimation(null);
             mWmService.mAnimator.removeDisplayLocked(mDisplayId);
             mInputMonitor.onDisplayRemoved();
-            // TODO(display-merge): Remove cast
-            mWmService.mDisplayNotificationController
-                .dispatchDisplayRemoved((ActivityDisplay) this);
+            mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
         } finally {
             mDisplayReady = false;
             mRemovingDisplay = false;
@@ -2610,6 +2744,29 @@
         }
     }
 
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
+            @WindowTraceLogLevel int logLevel) {
+        final long token = proto.start(fieldId);
+        dumpDebugInner(proto, DISPLAY, logLevel);
+        proto.write(com.android.server.am.ActivityDisplayProto.ID, mDisplayId);
+        proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
+        final ActivityStack focusedStack = getFocusedStack();
+        if (focusedStack != null) {
+            proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
+            final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
+            if (focusedActivity != null) {
+                focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+            }
+        } else {
+            proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
+        }
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            stack.dumpDebug(proto, com.android.server.am.ActivityDisplayProto.STACKS, logLevel);
+        }
+        proto.end(token);
+    }
+
     // TODO(proto-merge): Remove once protos for ActivityDisplay and DisplayContent are merged.
     public void dumpDebugInner(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
@@ -2670,7 +2827,9 @@
     @Override
     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
-        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
+        pw.print(prefix);
+        pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getStackCount() + (
+                mSingleTaskInstance ? " mSingleTaskInstance" : ""));
         final String subPrefix = "  " + prefix;
         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
         pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
@@ -2706,6 +2865,12 @@
         if (mLastFocus != mCurrentFocus) {
             pw.print("  mLastFocus="); pw.println(mLastFocus);
         }
+        if (mPreferredTopFocusableStack != null) {
+            pw.println(prefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+        }
+        if (mLastFocusedStack != null) {
+            pw.println(prefix + "mLastFocusedStack=" + mLastFocusedStack);
+        }
         if (mLosingFocus.size() > 0) {
             pw.println();
             pw.println("  Windows losing focus:");
@@ -2783,6 +2948,10 @@
         if (splitScreenPrimaryStack != null) {
             pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
         }
+        final ActivityStack recentsStack = getRecentsStack();
+        if (recentsStack != null) {
+            pw.println(prefix + "recentsStack=" + recentsStack.getName());
+        }
 
         pw.println();
         mDividerControllerLocked.dump(prefix, pw);
@@ -4068,8 +4237,7 @@
                             + " already exist on display=" + this + " stack=" + stack);
                 }
                 mSplitScreenPrimaryStack = stack;
-                // TODO(display-merge): Remove cast
-                ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeActivated();
+                mDisplayContent.onSplitScreenModeActivated();
                 mDividerControllerLocked.notifyDockedStackExistsChanged(true);
             }
         }
@@ -4083,8 +4251,7 @@
                 mPinnedStack = null;
             } else if (stack == mSplitScreenPrimaryStack) {
                 mSplitScreenPrimaryStack = null;
-                // TODO(display-merge): Remove cast
-                ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeDismissed();
+                mDisplayContent.onSplitScreenModeDismissed();
                 // Re-set the split-screen create mode whenever the split-screen stack is removed.
                 mWmService.setDockedStackCreateStateLocked(
                         SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
@@ -4109,8 +4276,7 @@
         @Override
         protected void removeChild(ActivityStack stack) {
             super.removeChild(stack);
-            // TODO(display-merge): Remove cast
-            ((ActivityDisplay) this.mDisplayContent).onStackRemoved(stack);
+            mDisplayContent.onStackRemoved(stack);
             removeStackReferenceIfNeeded(stack);
         }
 
@@ -5342,4 +5508,1132 @@
         }
         return mMetricsLogger;
     }
+
+    void onDisplayChanged() {
+        // The window policy is responsible for stopping activities on the default display.
+        final int displayId = mDisplay.getDisplayId();
+        if (displayId != DEFAULT_DISPLAY) {
+            final int displayState = mDisplay.getState();
+            if (displayState == Display.STATE_OFF && mOffToken == null) {
+                mOffToken = mAtmService.acquireSleepToken("Display-off", displayId);
+            } else if (displayState == Display.STATE_ON && mOffToken != null) {
+                mOffToken.release();
+                mOffToken = null;
+            }
+        }
+
+        mDisplay.getRealSize(mTmpDisplaySize);
+        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
+        updateDisplayInfo();
+        mWmService.requestTraversal();
+    }
+
+    void addStack(ActivityStack stack, int position) {
+        setStackOnDisplay(stack, position);
+        positionStackAt(stack, position);
+        mAtmService.updateSleepIfNeededLocked();
+    }
+
+    void onStackRemoved(ActivityStack stack) {
+        if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+            Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
+        }
+        if (mPreferredTopFocusableStack == stack) {
+            mPreferredTopFocusableStack = null;
+        }
+        releaseSelfIfNeeded();
+        mAtmService.updateSleepIfNeededLocked();
+        onStackOrderChanged(stack);
+    }
+
+    void positionStackAtTop(ActivityStack stack, boolean includingParents) {
+        positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
+    }
+
+    void positionStackAtTop(ActivityStack stack, boolean includingParents,
+            String updateLastFocusedStackReason) {
+        positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
+    }
+
+    void positionStackAtBottom(ActivityStack stack) {
+        positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
+    }
+
+    void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
+        positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
+    }
+
+    private void positionStackAt(ActivityStack stack, int position) {
+        positionStackAt(stack, position, false /* includingParents */,
+                null /* updateLastFocusedStackReason */);
+    }
+
+    private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
+            String updateLastFocusedStackReason) {
+        // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
+        //       the position internally, also update the logic here
+        final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
+                ? getFocusedStack() : null;
+        final boolean wasContained = getIndexOf(stack) >= 0;
+        if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
+            throw new IllegalStateException(
+                    "positionStackAt: Can only have one task on display=" + this);
+        }
+
+        // Since positionChildAt() is called during the creation process of pinned stacks,
+        // ActivityStack#getStack() can be null.
+        positionStackAt(position, stack, includingParents);
+
+        // The insert position may be adjusted to non-top when there is always-on-top stack. Since
+        // the original position is preferred to be top, the stack should have higher priority when
+        // we are looking for top focusable stack. The condition {@code wasContained} restricts the
+        // preferred stack is set only when moving an existing stack to top instead of adding a new
+        // stack that may be too early (e.g. in the middle of launching or reparenting).
+        if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
+            mPreferredTopFocusableStack = stack;
+        } else if (mPreferredTopFocusableStack == stack) {
+            mPreferredTopFocusableStack = null;
+        }
+
+        if (updateLastFocusedStackReason != null) {
+            final ActivityStack currentFocusedStack = getFocusedStack();
+            if (currentFocusedStack != prevFocusedStack) {
+                mLastFocusedStack = prevFocusedStack;
+                EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
+                        currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
+                        mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
+                        updateLastFocusedStackReason);
+            }
+        }
+
+        onStackOrderChanged(stack);
+    }
+
+    ActivityStack getStack(int stackId) {
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
+            if (stack.mStackId == stackId) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
+    boolean alwaysCreateStack(int windowingMode, int activityType) {
+        // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
+        // modes so that we can manage visual ordering and return types correctly.
+        return activityType == ACTIVITY_TYPE_STANDARD
+                && (windowingMode == WINDOWING_MODE_FULLSCREEN
+                || windowingMode == WINDOWING_MODE_FREEFORM
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+    }
+
+    /**
+     * Returns an existing stack compatible with the windowing mode and activity type or creates one
+     * if a compatible stack doesn't exist.
+     * @see #getStack(int, int)
+     * @see #createStack(int, int, boolean)
+     */
+    ActivityStack getOrCreateStack(int windowingMode, int activityType,
+            boolean onTop) {
+        if (!alwaysCreateStack(windowingMode, activityType)) {
+            ActivityStack stack = getStack(windowingMode, activityType);
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return createStack(windowingMode, activityType, onTop);
+    }
+
+    /**
+     * Returns an existing stack compatible with the input params or creates one
+     * if a compatible stack doesn't exist.
+     * @see #getOrCreateStack(int, int, boolean)
+     */
+    ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
+            @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
+            boolean onTop) {
+        // First preference is the windowing mode in the activity options if set.
+        int windowingMode = (options != null)
+                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+        // Validate that our desired windowingMode will work under the current conditions.
+        // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
+        // it's display's windowing mode.
+        windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
+        return getOrCreateStack(windowingMode, activityType, onTop);
+    }
+
+    @VisibleForTesting
+    int getNextStackId() {
+        return sNextFreeStackId++;
+    }
+
+    /**
+     * Creates a stack matching the input windowing mode and activity type on this display.
+     * @param windowingMode The windowing mode the stack should be created in. If
+     *                      {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
+     *                      inherit its parent's windowing mode.
+     * @param activityType The activityType the stack should be created in. If
+     *                     {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
+     *                     be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+     * @param onTop If true the stack will be created at the top of the display, else at the bottom.
+     * @return The newly created stack.
+     */
+    ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
+        if (mSingleTaskInstance && getStackCount() > 0) {
+            // Create stack on default display instead since this display can only contain 1 stack.
+            // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
+            // this goes away once ActivityView is no longer using virtual displays.
+            return mRootActivityContainer.getDefaultDisplay().createStack(
+                    windowingMode, activityType, onTop);
+        }
+
+        if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+            // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
+            // anything else should be passing it in anyways...
+            activityType = ACTIVITY_TYPE_STANDARD;
+        }
+
+        if (activityType != ACTIVITY_TYPE_STANDARD) {
+            // For now there can be only one stack of a particular non-standard activity type on a
+            // display. So, get that ignoring whatever windowing mode it is currently in.
+            ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+            if (stack != null) {
+                throw new IllegalArgumentException("Stack=" + stack + " of activityType="
+                        + activityType + " already on display=" + this + ". Can't have multiple.");
+            }
+        }
+
+        if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
+                mAtmService.mSupportsSplitScreenMultiWindow,
+                mAtmService.mSupportsFreeformWindowManagement,
+                mAtmService.mSupportsPictureInPicture, activityType)) {
+            throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
+                    + windowingMode);
+        }
+
+        final int stackId = getNextStackId();
+        return createStackUnchecked(windowingMode, activityType, stackId, onTop);
+    }
+
+    @VisibleForTesting
+    ActivityStack createStackUnchecked(int windowingMode, int activityType,
+            int stackId, boolean onTop) {
+        if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+            throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+                    + "activity type.");
+        }
+        return new ActivityStack(this, stackId, mRootActivityContainer.mStackSupervisor,
+                windowingMode, activityType, onTop);
+    }
+
+    /**
+     * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
+     * focusable and visible stack from the top of stacks in this display.
+     */
+    ActivityStack getFocusedStack() {
+        if (mPreferredTopFocusableStack != null) {
+            return mPreferredTopFocusableStack;
+        }
+
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
+            if (stack.isFocusableAndVisible()) {
+                return stack;
+            }
+        }
+
+        return null;
+    }
+
+    ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
+        final int currentWindowingMode = currentFocus != null
+                ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+        ActivityStack candidate = null;
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
+            if (ignoreCurrent && stack == currentFocus) {
+                continue;
+            }
+            if (!stack.isFocusableAndVisible()) {
+                continue;
+            }
+
+            if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                    && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+                // If the currently focused stack is in split-screen secondary we save off the
+                // top primary split-screen stack as a candidate for focus because we might
+                // prefer focus to move to an other stack to avoid primary split-screen stack
+                // overlapping with a fullscreen stack when a fullscreen stack is higher in z
+                // than the next split-screen stack. Assistant stack, I am looking at you...
+                // We only move the focus to the primary-split screen stack if there isn't a
+                // better alternative.
+                candidate = stack;
+                continue;
+            }
+            if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+                // Use the candidate stack since we are now at the secondary split-screen.
+                return candidate;
+            }
+            return stack;
+        }
+        return candidate;
+    }
+
+    ActivityRecord getResumedActivity() {
+        final ActivityStack focusedStack = getFocusedStack();
+        if (focusedStack == null) {
+            return null;
+        }
+        // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
+        // Check if the focused stack has the resumed activity
+        ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+        if (resumedActivity == null || resumedActivity.app == null) {
+            // If there is no registered resumed activity in the stack or it is not running -
+            // try to use previously resumed one.
+            resumedActivity = focusedStack.mPausingActivity;
+            if (resumedActivity == null || resumedActivity.app == null) {
+                // If previously resumed activity doesn't work either - find the topmost running
+                // activity that can be focused.
+                resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
+            }
+        }
+        return resumedActivity;
+    }
+
+    ActivityStack getLastFocusedStack() {
+        return mLastFocusedStack;
+    }
+
+    boolean allResumedActivitiesComplete() {
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
+            if (r != null && !r.isState(RESUMED)) {
+                return false;
+            }
+        }
+        final ActivityStack currentFocusedStack = getFocusedStack();
+        if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+            Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+                    + mLastFocusedStack + " to=" + currentFocusedStack);
+        }
+        mLastFocusedStack = currentFocusedStack;
+        return true;
+    }
+
+    /**
+     * Pause all activities in either all of the stacks or just the back stacks. This is done before
+     * resuming a new activity and to make sure that previously active activities are
+     * paused in stacks that are no longer visible or in pinned windowing mode. This does not
+     * pause activities in visible stacks, so if an activity is launched within the same stack/task,
+     * then we should explicitly pause that stack's top activity.
+     * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
+     * @param resuming The resuming activity.
+     * @return {@code true} if any activity was paused as a result of this call.
+     */
+    boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
+        boolean someActivityPaused = false;
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            final ActivityRecord resumedActivity = stack.getResumedActivity();
+            if (resumedActivity != null
+                    && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+                    || !stack.isFocusable())) {
+                if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
+                        + " mResumedActivity=" + resumedActivity);
+                someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
+                        resuming);
+            }
+        }
+        return someActivityPaused;
+    }
+
+    /**
+     * Find task for putting the Activity in.
+     */
+    void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
+            RootActivityContainer.FindTaskResult result) {
+        mTmpFindTaskResult.clear();
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            if (!r.hasCompatibleActivityType(stack)) {
+                if (DEBUG_TASKS) {
+                    Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
+                }
+                continue;
+            }
+
+            mTmpFindTaskResult.process(r, stack);
+            // It is possible to have tasks in multiple stacks with the same root affinity, so
+            // we should keep looking after finding an affinity match to see if there is a
+            // better match in another stack. Also, task affinity isn't a good enough reason
+            // to target a display which isn't the source of the intent, so skip any affinity
+            // matches not on the specified display.
+            if (mTmpFindTaskResult.mRecord != null) {
+                if (mTmpFindTaskResult.mIdealMatch) {
+                    result.setTo(mTmpFindTaskResult);
+                    return;
+                } else if (isPreferredDisplay) {
+                    // Note: since the traversing through the stacks is top down, the floating
+                    // tasks should always have lower priority than any affinity-matching tasks
+                    // in the fullscreen stacks
+                    result.setTo(mTmpFindTaskResult);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes stacks in the input windowing modes from the system if they are of activity type
+     * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+     */
+    void removeStacksInWindowingModes(int... windowingModes) {
+        if (windowingModes == null || windowingModes.length == 0) {
+            return;
+        }
+
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
+        for (int j = windowingModes.length - 1; j >= 0; --j) {
+            final int windowingMode = windowingModes[j];
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
+                if (!stack.isActivityTypeStandardOrUndefined()) {
+                    continue;
+                }
+                if (stack.getWindowingMode() != windowingMode) {
+                    continue;
+                }
+                stacks.add(stack);
+            }
+        }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
+    }
+
+    void removeStacksWithActivityTypes(int... activityTypes) {
+        if (activityTypes == null || activityTypes.length == 0) {
+            return;
+        }
+
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
+        for (int j = activityTypes.length - 1; j >= 0; --j) {
+            final int activityType = activityTypes[j];
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
+                if (stack.getActivityType() == activityType) {
+                    stacks.add(stack);
+                }
+            }
+        }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
+    }
+
+    void onSplitScreenModeDismissed() {
+        mAtmService.deferWindowLayout();
+        try {
+            // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getStackAt(i);
+                if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
+                    continue;
+                }
+                otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
+                        false /* showRecents */, false /* enteringSplitScreenMode */,
+                        true /* deferEnsuringVisibility */, false /* creating */);
+            }
+        } finally {
+            final ActivityStack topFullscreenStack =
+                    getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+            final ActivityStack homeStack = getHomeStack();
+            if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
+                // Whenever split-screen is dismissed we want the home stack directly behind the
+                // current top fullscreen stack so it shows up when the top stack is finished.
+                // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
+                // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
+                // once we have that.
+                homeStack.moveToFront("onSplitScreenModeDismissed");
+                topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
+            }
+            mAtmService.continueWindowLayout();
+        }
+    }
+
+    void onSplitScreenModeActivated() {
+        mAtmService.deferWindowLayout();
+        try {
+            // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
+            final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getStackAt(i);
+                if (otherStack == splitScreenPrimaryStack
+                        || !otherStack.affectedBySplitScreenResize()) {
+                    continue;
+                }
+                otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+                        false /* animate */, false /* showRecents */,
+                        true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
+                        false /* creating */);
+            }
+        } finally {
+            mAtmService.continueWindowLayout();
+        }
+    }
+
+    /**
+     * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
+     * @param windowingMode The windowing mode we are checking support for.
+     * @param supportsMultiWindow If we should consider support for multi-window mode in general.
+     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
+     * @param supportsFreeform If we should consider support for freeform multi-window.
+     * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+     * @param activityType The activity type under consideration.
+     * @return true if the windowing mode is supported.
+     */
+    private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
+            int activityType) {
+
+        if (windowingMode == WINDOWING_MODE_UNDEFINED
+                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            return true;
+        }
+        if (!supportsMultiWindow) {
+            return false;
+        }
+
+        final int displayWindowingMode = getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+            return supportsSplitScreen
+                    && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
+                    // Freeform windows and split-screen windows don't mix well, so prevent
+                    // split windowing modes on freeform displays.
+                    && displayWindowingMode != WINDOWING_MODE_FREEFORM;
+        }
+
+        if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
+            return false;
+        }
+
+        if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
+     * display with the provided parameters.
+     *
+     * @param r The ActivityRecord in question.
+     * @param options Options to start with.
+     * @param task The task within-which the activity would start.
+     * @param activityType The type of activity to start.
+     * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
+     */
+    int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+            @Nullable Task task, int activityType) {
+
+        // First preference if the windowing mode in the activity options if set.
+        int windowingMode = (options != null)
+                ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+        // If windowing mode is unset, then next preference is the candidate task, then the
+        // activity record.
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            if (task != null) {
+                windowingMode = task.getWindowingMode();
+            }
+            if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+                windowingMode = r.getWindowingMode();
+            }
+            if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+                // Use the display's windowing mode.
+                windowingMode = getWindowingMode();
+            }
+        }
+        windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
+        return windowingMode != WINDOWING_MODE_UNDEFINED
+                ? windowingMode : WINDOWING_MODE_FULLSCREEN;
+    }
+
+    /**
+     * Check that the requested windowing-mode is appropriate for the specified task and/or activity
+     * on this display.
+     *
+     * @param windowingMode The windowing-mode to validate.
+     * @param r The {@link ActivityRecord} to check against.
+     * @param task The {@link Task} to check against.
+     * @param activityType An activity type.
+     * @return The provided windowingMode or the closest valid mode which is appropriate.
+     */
+    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+            int activityType) {
+        // Make sure the windowing mode we are trying to use makes sense for what is supported.
+        boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
+        boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
+        boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
+        boolean supportsPip = mAtmService.mSupportsPictureInPicture;
+        if (supportsMultiWindow) {
+            if (task != null) {
+                supportsMultiWindow = task.isResizeable();
+                supportsSplitScreen = task.supportsSplitScreenWindowingMode();
+                // TODO: Do we need to check for freeform and Pip support here?
+            } else if (r != null) {
+                supportsMultiWindow = r.isResizeable();
+                supportsSplitScreen = r.supportsSplitScreenWindowingMode();
+                supportsFreeform = r.supportsFreeform();
+                supportsPip = r.supportsPictureInPicture();
+            }
+        }
+
+        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
+        if (!inSplitScreenMode
+                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+            // Switch to the display's windowing mode if we are not in split-screen mode and we are
+            // trying to launch in split-screen secondary.
+            windowingMode = WINDOWING_MODE_UNDEFINED;
+        } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
+                || windowingMode == WINDOWING_MODE_UNDEFINED)
+                && supportsSplitScreen) {
+            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+        }
+
+        if (windowingMode != WINDOWING_MODE_UNDEFINED
+                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+                supportsFreeform, supportsPip, activityType)) {
+            return windowingMode;
+        }
+        return WINDOWING_MODE_UNDEFINED;
+    }
+
+    boolean isTopStack(ActivityStack stack) {
+        return stack == getTopStack();
+    }
+
+    boolean isTopNotPinnedStack(ActivityStack stack) {
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack current = getStackAt(i);
+            if (!current.inPinnedWindowingMode()) {
+                return current == stack;
+            }
+        }
+        return false;
+    }
+
+    ActivityRecord topRunningActivity() {
+        return topRunningActivity(false /* considerKeyguardState */);
+    }
+
+    /**
+     * Returns the top running activity in the focused stack. In the case the focused stack has no
+     * such activity, the next focusable stack on this display is returned.
+     *
+     * @param considerKeyguardState Indicates whether the locked state should be considered. if
+     *                              {@code true} and the keyguard is locked, only activities that
+     *                              can be shown on top of the keyguard will be considered.
+     * @return The top running activity. {@code null} if none is available.
+     */
+    ActivityRecord topRunningActivity(boolean considerKeyguardState) {
+        ActivityRecord topRunning = null;
+        final ActivityStack focusedStack = getFocusedStack();
+        if (focusedStack != null) {
+            topRunning = focusedStack.topRunningActivity();
+        }
+
+        // Look in other focusable stacks.
+        if (topRunning == null) {
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
+                // Only consider focusable stacks other than the current focused one.
+                if (stack == focusedStack || !stack.isFocusable()) {
+                    continue;
+                }
+                topRunning = stack.topRunningActivity();
+                if (topRunning != null) {
+                    break;
+                }
+            }
+        }
+
+        // This activity can be considered the top running activity if we are not considering
+        // the locked state, the keyguard isn't locked, or we can show when locked.
+        if (topRunning != null && considerKeyguardState
+                && mRootActivityContainer.mStackSupervisor.getKeyguardController()
+                        .isKeyguardLocked()
+                && !topRunning.canShowWhenLocked()) {
+            return null;
+        }
+
+        return topRunning;
+    }
+
+    boolean updateDisplayOverrideConfigurationLocked() {
+        Configuration values = new Configuration();
+        computeScreenConfiguration(values);
+
+        mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
+                ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,
+                mDisplayId));
+
+        Settings.System.clearConfiguration(values);
+        updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+                false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
+        return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
+    }
+
+    /**
+     * Updates override configuration specific for the selected display. If no config is provided,
+     * new one will be computed in WM based on current display info.
+     */
+    boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+            ActivityRecord starting, boolean deferResume,
+            ActivityTaskManagerService.UpdateConfigurationResult result) {
+
+        int changes = 0;
+        boolean kept = true;
+
+        mAtmService.deferWindowLayout();
+        try {
+            if (values != null) {
+                if (mDisplayId == DEFAULT_DISPLAY) {
+                    // Override configuration of the default display duplicates global config, so
+                    // we're calling global config update instead for default display. It will also
+                    // apply the correct override config.
+                    changes = mAtmService.updateGlobalConfigurationLocked(values,
+                            false /* initLocale */, false /* persistent */,
+                            UserHandle.USER_NULL /* userId */, deferResume);
+                } else {
+                    changes = performDisplayOverrideConfigUpdate(values, deferResume);
+                }
+            }
+
+            kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
+        } finally {
+            mAtmService.continueWindowLayout();
+        }
+
+        if (result != null) {
+            result.changes = changes;
+            result.activityRelaunched = !kept;
+        }
+        return kept;
+    }
+
+    int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
+        mTempConfig.setTo(getRequestedOverrideConfiguration());
+        final int changes = mTempConfig.updateFrom(values);
+        if (changes != 0) {
+            Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+                    + mTempConfig + " for displayId=" + mDisplayId);
+            onRequestedOverrideConfigurationChanged(mTempConfig);
+
+            final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+            if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
+                mAtmService.mAppWarnings.onDensityChanged();
+
+                // Post message to start process to avoid possible deadlock of calling into AMS with
+                // the ATMS lock held.
+                final Message msg = PooledLambda.obtainMessage(
+                        ActivityManagerInternal::killAllBackgroundProcessesExcept,
+                        mAtmService.mAmInternal, N,
+                        ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+                mAtmService.mH.sendMessage(msg);
+            }
+            mWmService.mDisplayNotificationController.dispatchDisplayChanged(
+                    this, getConfiguration());
+        }
+        return changes;
+    }
+
+    @Override
+    public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+        final int currRotation =
+                getRequestedOverrideConfiguration().windowConfiguration.getRotation();
+        if (currRotation != ROTATION_UNDEFINED
+                && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
+            applyRotationLocked(currRotation,
+                    overrideConfiguration.windowConfiguration.getRotation());
+        }
+        mCurrentOverrideConfigurationChanges =
+            getRequestedOverrideConfiguration().diff(overrideConfiguration);
+        super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+        mCurrentOverrideConfigurationChanges = 0;
+        mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
+        mAtmService.addWindowLayoutReasons(
+                ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
+    }
+
+    /** Checks whether the given activity is in size compatibility mode and notifies the change. */
+    void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
+        if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+            // The callback is only interested in the foreground changes of fullscreen activity.
+            return;
+        }
+        if (!r.inSizeCompatMode()) {
+            if (mLastCompatModeActivity != null) {
+                mAtmService.getTaskChangeNotificationController()
+                        .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
+            }
+            mLastCompatModeActivity = null;
+            return;
+        }
+        if (mLastCompatModeActivity == r) {
+            return;
+        }
+        mLastCompatModeActivity = r;
+        mAtmService.getTaskChangeNotificationController()
+                .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
+    }
+
+    boolean isUidPresent(int uid) {
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+        final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
+        p.recycle();
+        return isUidPresent;
+    }
+
+    /**
+     * @see #mRemoved
+     */
+    boolean isRemoved() {
+        return mRemoved;
+    }
+
+    /**
+     * @see #mRemoving
+     */
+    boolean isRemoving() {
+        return mRemoving;
+    }
+
+    void remove() {
+        mRemoving = true;
+        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+        ActivityStack lastReparentedStack = null;
+        mPreferredTopFocusableStack = null;
+
+        // Stacks could be reparented from the removed display to other display. While
+        // reparenting the last stack of the removed display, the remove display is ready to be
+        // released (no more ActivityStack). But, we cannot release it at that moment or the
+        // related WindowContainer will also be removed. So, we set display as removed after
+        // reparenting stack finished.
+        final DisplayContent toDisplay = mRootActivityContainer.getDefaultDisplay();
+        mRootActivityContainer.mStackSupervisor.beginDeferResume();
+        try {
+            int numStacks = getStackCount();
+            // Keep the order from bottom to top.
+            for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+                final ActivityStack stack = getStackAt(stackNdx);
+                // Always finish non-standard type stacks.
+                if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+                    stack.finishAllActivitiesImmediately();
+                } else {
+                    // If default display is in split-window mode, set windowing mode of the stack
+                    // to split-screen secondary. Otherwise, set the windowing mode to undefined by
+                    // default to let stack inherited the windowing mode from the new display.
+                    final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
+                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                            : WINDOWING_MODE_UNDEFINED;
+                    stack.reparent(toDisplay, true /* onTop */);
+                    stack.setWindowingMode(windowingMode);
+                    lastReparentedStack = stack;
+                }
+                // Stacks may be removed from this display. Ensure each stack will be processed and
+                // the loop will end.
+                stackNdx -= numStacks - getStackCount();
+                numStacks = getStackCount();
+            }
+        } finally {
+            mRootActivityContainer.mStackSupervisor.endDeferResume();
+        }
+        mRemoved = true;
+
+        // Only update focus/visibility for the last one because there may be many stacks are
+        // reparented and the intermediate states are unnecessary.
+        if (lastReparentedStack != null) {
+            lastReparentedStack.postReparent();
+        }
+        releaseSelfIfNeeded();
+
+        if (!mAllSleepTokens.isEmpty()) {
+            mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
+            mAllSleepTokens.clear();
+            mAtmService.updateSleepIfNeededLocked();
+        }
+    }
+
+    private void releaseSelfIfNeeded() {
+        if (!mRemoved) {
+            return;
+        }
+
+        final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
+        if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
+            // Release this display if an empty home stack is the only thing left.
+            // Since it is the last stack, this display will be released along with the stack
+            // removal.
+            stack.removeIfPossible();
+        } else if (getTopStack() == null) {
+            removeIfPossible();
+            mRootActivityContainer.removeChild(this);
+            mRootActivityContainer.mStackSupervisor
+                    .getKeyguardController().onDisplayRemoved(mDisplayId);
+        }
+    }
+
+    /** Update and get all UIDs that are present on the display and have access to it. */
+    IntArray getPresentUIDs() {
+        mDisplayAccessUIDs.clear();
+        final PooledConsumer c = PooledLambda.obtainConsumer(DisplayContent::addActivityUid,
+                PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
+        mDisplayContent.forAllActivities(c);
+        c.recycle();
+        return mDisplayAccessUIDs;
+    }
+
+    private static void addActivityUid(ActivityRecord r, IntArray uids) {
+        uids.add(r.getUid());
+    }
+
+    @VisibleForTesting
+    boolean shouldDestroyContentOnRemove() {
+        return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
+    }
+
+    boolean shouldSleep() {
+        return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
+                && (mAtmService.mRunningVoice == null);
+    }
+
+    void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
+        final ActivityRecord newFocus;
+        final IBinder token = r.appToken;
+        if (token == null) {
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
+                    mDisplayId);
+            newFocus = null;
+        } else {
+            newFocus = mWmService.mRoot.getActivityRecord(token);
+            if (newFocus == null) {
+                Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
+                        + ", displayId=" + mDisplayId);
+            }
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+                    "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
+                    moveFocusNow, mDisplayId);
+        }
+
+        final boolean changed = setFocusedApp(newFocus);
+        if (moveFocusNow && changed) {
+            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+                    true /*updateInputWindows*/);
+        }
+    }
+
+    /**
+     * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
+     *         already top-most.
+     */
+    ActivityStack getStackAbove(ActivityStack stack) {
+        final int stackIndex = getIndexOf(stack) + 1;
+        return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
+    }
+
+    /**
+     * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
+     * Generally used in conjunction with {@link #moveStackBehindStack}.
+     */
+    void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
+        if (stack.shouldBeVisible(null)) {
+            // Skip if the stack is already visible
+            return;
+        }
+
+        // Move the stack to the bottom to not affect the following visibility checks
+        positionStackAtBottom(stack);
+
+        // Find the next position where the stack should be placed
+        final int numStacks = getStackCount();
+        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+            final ActivityStack s = getStackAt(stackNdx);
+            if (s == stack) {
+                continue;
+            }
+            final int winMode = s.getWindowingMode();
+            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
+                    || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            if (s.shouldBeVisible(null) && isValidWindowingMode) {
+                // Move the provided stack to behind this stack
+                positionStackAt(stack, Math.max(0, stackNdx - 1));
+                break;
+            }
+        }
+    }
+
+    /**
+     * Moves the {@param stack} behind the given {@param behindStack} if possible. If
+     * {@param behindStack} is not currently in the display, then then the stack is moved to the
+     * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
+     */
+    void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
+        if (behindStack == null || behindStack == stack) {
+            return;
+        }
+
+        // Note that positionChildAt will first remove the given stack before inserting into the
+        // list, so we need to adjust the insertion index to account for the removed index
+        // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
+        //       position internally
+        final int stackIndex = getIndexOf(stack);
+        final int behindStackIndex = getIndexOf(behindStack);
+        final int insertIndex = stackIndex <= behindStackIndex
+                ? behindStackIndex - 1 : behindStackIndex;
+        positionStackAt(stack, Math.max(0, insertIndex));
+    }
+
+    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+                    notifyClients);
+        }
+    }
+
+    void moveHomeStackToFront(String reason) {
+        final ActivityStack homeStack = getHomeStack();
+        if (homeStack != null) {
+            homeStack.moveToFront(reason);
+        }
+    }
+
+    /**
+     * Moves the focusable home activity to top. If there is no such activity, the home stack will
+     * still move to top.
+     */
+    void moveHomeActivityToTop(String reason) {
+        final ActivityRecord top = getHomeActivity();
+        if (top == null) {
+            moveHomeStackToFront(reason);
+            return;
+        }
+        top.moveFocusableActivityToTop(reason);
+    }
+
+    @Nullable
+    ActivityRecord getHomeActivity() {
+        return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
+    }
+
+    @Nullable
+    ActivityRecord getHomeActivityForUser(int userId) {
+        final ActivityStack homeStack = getHomeStack();
+        if (homeStack == null) {
+            return null;
+        }
+
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                DisplayContent::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+                userId);
+        final ActivityRecord r = homeStack.getActivity(p);
+        p.recycle();
+        return r;
+    }
+
+    private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
+        return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
+    }
+
+    boolean isSleeping() {
+        return mSleeping;
+    }
+
+    void setIsSleeping(boolean asleep) {
+        mSleeping = asleep;
+    }
+
+    /**
+     * Adds a listener to be notified whenever the stack order in the display changes. Currently
+     * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
+     * current animation when the system state changes.
+     */
+    void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
+        if (!mStackOrderChangedCallbacks.contains(listener)) {
+            mStackOrderChangedCallbacks.add(listener);
+        }
+    }
+
+    /**
+     * Removes a previously registered stack order change listener.
+     */
+    void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
+        mStackOrderChangedCallbacks.remove(listener);
+    }
+
+    /**
+     * Notifies of a stack order change
+     * @param stack The stack which triggered the order change
+     */
+    private void onStackOrderChanged(ActivityStack stack) {
+        for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
+            mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
+        }
+    }
+
+    void setDisplayToSingleTaskInstance() {
+        final int childCount = getStackCount();
+        if (childCount > 1) {
+            throw new IllegalArgumentException("Display already has multiple stacks. display="
+                    + this);
+        }
+        if (childCount > 0) {
+            final ActivityStack stack = getStackAt(0);
+            if (stack.getChildCount() > 1) {
+                throw new IllegalArgumentException("Display stack already has multiple tasks."
+                        + " display=" + this + " stack=" + stack);
+            }
+        }
+
+        mSingleTaskInstance = true;
+    }
+
+    /** Returns true if the display can only contain one task */
+    boolean isSingleTaskInstance() {
+        return mSingleTaskInstance;
+    }
+
+    @VisibleForTesting
+    void removeAllTasks() {
+        forAllTasks((t) -> { t.getStack().removeChild(t, "removeAllTasks"); });
+    }
+
+    /**
+     * Callback for when the order of the stacks in the display changes.
+     */
+    interface OnStackOrderChangedListener {
+        void onStackOrderChanged(ActivityStack stack);
+    }
+
+    public void dumpStacks(PrintWriter pw) {
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            pw.print(getStackAt(i).mStackId);
+            if (i > 0) {
+                pw.print(",");
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2283041..667e713 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -33,6 +33,7 @@
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.ITYPE_TOP_GESTURES;
 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
@@ -49,7 +50,6 @@
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -63,6 +63,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -149,13 +150,17 @@
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.InsetsFlags;
+import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewRootImpl;
-import android.view.WindowInsets;
+import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Side.InsetsSide;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -337,6 +342,7 @@
     private int mLastAppearance;
     private int mLastFullscreenAppearance;
     private int mLastDockedAppearance;
+    private int mLastBehavior;
     private final Rect mNonDockedStackBounds = new Rect();
     private final Rect mDockedStackBounds = new Rect();
     private final Rect mLastNonDockedStackBounds = new Rect();
@@ -353,6 +359,7 @@
     private static final Rect sTmpRect = new Rect();
     private static final Rect sTmpNavFrame = new Rect();
     private static final Rect sTmpLastParentFrame = new Rect();
+    private static final int[] sTmpTypesAndSides = new int[2];
 
     private WindowState mTopFullscreenOpaqueWindowState;
     private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -1228,7 +1235,8 @@
         final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
 
         if (layoutInScreenAndInsetDecor && !screenDecor) {
-            if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+            if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                    || (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) == 0) {
                 outFrame.set(displayFrames.mUnrestricted);
             } else {
                 outFrame.set(displayFrames.mRestricted);
@@ -1281,11 +1289,27 @@
         }
     }
 
+    private static void getImpliedTypesAndSidesToFit(LayoutParams attrs, int[] typesAndSides) {
+        typesAndSides[0] = attrs.getFitWindowInsetsTypes();
+        typesAndSides[1] = attrs.getFitWindowInsetsSides();
+        final boolean forceDrawsBarBackgrounds =
+                (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
+                        && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
+        if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || forceDrawsBarBackgrounds) {
+            if ((attrs.privateFlags & PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND) != 0) {
+                typesAndSides[1] &= ~Side.BOTTOM;
+            } else {
+                typesAndSides[0] &= ~Type.systemBars();
+            }
+        }
+    }
+
+    // TODO(b/118118435): remove after migration
     private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
         int impliedFlags = 0;
         final boolean forceWindowDrawsBarBackgrounds =
                 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
-                && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
+                        && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                 || forceWindowDrawsBarBackgrounds) {
             impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -1300,6 +1324,13 @@
             synchronized (mLock) {
                 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                 mDisplayContent.reevaluateStatusBarVisibility();
+                if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL && mNavigationBar != null) {
+                    final InsetsControlTarget target =
+                            mNavigationBar.getControllableInsetProvider().getControlTarget();
+                    if (target != null) {
+                        target.showInsets(Type.navigationBars(), false /* fromIme */);
+                    }
+                }
             }
         }
     };
@@ -1376,11 +1407,18 @@
         // For purposes of putting out fake window up to steal focus, we will
         // drive nav being hidden only by whether it is requested.
         final int sysui = mLastSystemUiFlags;
-        boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+        final int behavior = mLastBehavior;
+        boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
+                ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+                : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null
+                        && mNavigationBar.getControllableInsetProvider().isClientVisible()
+                        && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
         boolean navTranslucent = (sysui
                 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
-        boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
-        boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+        boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
+                || (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
+        boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
+                || (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
         boolean navAllowedHidden = immersive || immersiveSticky;
         navTranslucent &= !immersiveSticky;  // transient trumps translucent
         boolean isKeyguardShowing = isStatusBarKeyguard()
@@ -1464,6 +1502,9 @@
                     displayFrames.mUnrestricted /* stableFrame */);
             w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
             w.computeFrameLw();
+            if (w.getControllableInsetProvider() != null) {
+                w.getControllableInsetProvider().updateSourceFrame();
+            }
             final Rect frame = w.getFrameLw();
 
             if (frame.left <= 0 && frame.top <= 0) {
@@ -1526,6 +1567,11 @@
         // Let the status bar determine its size.
         mStatusBar.computeFrameLw();
 
+        // Update the source frame to provide insets to other windows during layout.
+        if (mStatusBar.getControllableInsetProvider() != null) {
+            mStatusBar.getControllableInsetProvider().updateSourceFrame();
+        }
+
         // For layout, the status bar is always at the top with our fixed height.
         displayFrames.mStable.top = displayFrames.mUnrestricted.top
                 + mStatusBarHeightForRotation[displayFrames.mRotation];
@@ -1540,7 +1586,8 @@
         sTmpRect.bottom = displayFrames.mStable.top;  // Use collapsed status bar size
         mStatusBarController.setContentFrame(sTmpRect);
 
-        boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+        boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
+                || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
         boolean statusBarTranslucent = (sysui
                 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
 
@@ -1676,6 +1723,9 @@
                 navigationFrame /* stableFrame */);
         mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
         mNavigationBar.computeFrameLw();
+        if (mNavigationBar.getControllableInsetProvider() != null) {
+            mNavigationBar.getControllableInsetProvider().updateSourceFrame();
+        }
         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
 
         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
@@ -1811,19 +1861,44 @@
 
         final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
 
-        final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
-                || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
-
         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
 
         sf.set(displayFrames.mStable);
 
-        if (type == TYPE_INPUT_METHOD) {
+        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+            getImpliedTypesAndSidesToFit(attrs, sTmpTypesAndSides);
+            final @InsetsType int typesToFit = sTmpTypesAndSides[0];
+            final @InsetsSide int sidesToFit = sTmpTypesAndSides[1];
+            final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
+            final Rect dfu = displayFrames.mUnrestricted;
+            Insets insets = Insets.of(0, 0, 0, 0);
+            for (int i = types.size() - 1; i >= 0; i--) {
+                insets = Insets.max(insets, mDisplayContent.getInsetsStateController()
+                        .getInsetsForDispatch(win).getSource(types.valueAt(i))
+                        .calculateInsets(dfu, attrs.getFitIgnoreVisibility()));
+            }
+            final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
+            final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
+            final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
+            final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
+            df.set(left, top, dfu.right - right, dfu.bottom - bottom);
+            if (attached == null) {
+                pf.set(df);
+                vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
+                        ? displayFrames.mCurrent : displayFrames.mDock);
+            } else {
+                pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
+                vf.set(attached.getVisibleFrameLw());
+            }
+            cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
+                    ? displayFrames.mDock : displayFrames.mContent);
+            dcf.set(displayFrames.mSystem);
+        } else if (type == TYPE_INPUT_METHOD) {
             vf.set(displayFrames.mDock);
             cf.set(displayFrames.mDock);
             df.set(displayFrames.mDock);
-            windowFrames.mParentFrame.set(displayFrames.mDock);
+            pf.set(displayFrames.mDock);
             // IM dock windows layout below the nav bar...
             pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
             // ...with content insets above the nav bar
@@ -1989,7 +2064,7 @@
                     }
                 }
             } else if (layoutInScreen || (sysUiFl
-                    & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                     | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
                         + "): IN_SCREEN");
@@ -2039,7 +2114,7 @@
                     cf.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
-                } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
+                } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
 
@@ -2111,8 +2186,12 @@
 
         final int cutoutMode = attrs.layoutInDisplayCutoutMode;
         final boolean attachedInParent = attached != null && !layoutInScreen;
+        final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
+                || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
+                || !win.getClientInsetsState().getSource(ITYPE_STATUS_BAR).isVisible();
         final boolean requestedHideNavigation =
-                (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+                (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                        || !win.getClientInsetsState().getSource(ITYPE_NAVIGATION_BAR).isVisible();
 
         // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
         // cropped / shifted to the displayFrame in WindowState.
@@ -2195,6 +2274,9 @@
         }
 
         win.computeFrameLw();
+        if (win.getControllableInsetProvider() != null) {
+            win.getControllableInsetProvider().updateSourceFrame();
+        }
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
         if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
@@ -2985,7 +3067,7 @@
                     mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
                             new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
                 } else {
-                    controlTarget.showInsets(WindowInsets.Type.systemBars(), false);
+                    controlTarget.showInsets(Type.systemBars(), false);
                 }
             } else {
                 boolean sb = mStatusBarController.checkShowTransientBarLw();
@@ -3109,6 +3191,7 @@
                 && mLastAppearance == appearance
                 && mLastFullscreenAppearance == fullscreenAppearance
                 && mLastDockedAppearance == dockedAppearance
+                && mLastBehavior == behavior
                 && mLastFocusIsFullscreen == isFullscreen
                 && mLastFocusIsImmersive == isImmersive
                 && mFocusedApp == win.getAppToken()
@@ -3125,6 +3208,7 @@
         mLastAppearance = appearance;
         mLastFullscreenAppearance = fullscreenAppearance;
         mLastDockedAppearance = dockedAppearance;
+        mLastBehavior = behavior;
         mLastFocusIsFullscreen = isFullscreen;
         mLastFocusIsImmersive = isImmersive;
         mFocusedApp = win.getAppToken();
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index 78fea74..bb31d45 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -41,7 +41,7 @@
             try {
                 for (int i = 0; i < mService.mAtmService.mRootActivityContainer.getChildCount();
                         ++i) {
-                    ActivityDisplay d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
+                    DisplayContent d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
                     listener.onDisplayAdded(d.mDisplayId);
                 }
             } catch (RemoteException e) { }
@@ -52,7 +52,7 @@
         mDisplayListeners.unregister(listener);
     }
 
-    void dispatchDisplayAdded(ActivityDisplay display) {
+    void dispatchDisplayAdded(DisplayContent display) {
         int count = mDisplayListeners.beginBroadcast();
         for (int i = 0; i < count; ++i) {
             try {
@@ -85,7 +85,7 @@
         mDisplayListeners.finishBroadcast();
     }
 
-    void dispatchDisplayRemoved(ActivityDisplay display) {
+    void dispatchDisplayRemoved(DisplayContent display) {
         int count = mDisplayListeners.beginBroadcast();
         for (int i = 0; i < count; ++i) {
             try {
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 82ac6b8..bef1442 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -46,6 +46,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -189,6 +190,7 @@
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                 PixelFormat.TRANSLUCENT);
+        lp.setFitWindowInsetsTypes(lp.getFitWindowInsetsTypes() & ~Type.statusBars());
         lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("ImmersiveModeConfirmation");
         lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index d50bcc4..af84836 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -45,7 +45,7 @@
     private final IntArray mShowingTransientTypes = new IntArray();
 
     private WindowState mFocusedWin;
-    private BarWindow mTopBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
+    private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
     private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
 
     InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
@@ -57,15 +57,15 @@
     /** Updates the target which can control system bars. */
     void updateBarControlTarget(@Nullable WindowState focusedWin) {
         mFocusedWin = focusedWin;
-        mStateController.onBarControlTargetChanged(getTopControlTarget(focusedWin),
-                getFakeTopControlTarget(focusedWin),
+        mStateController.onBarControlTargetChanged(getStatusControlTarget(focusedWin),
+                getFakeStatusControlTarget(focusedWin),
                 getNavControlTarget(focusedWin),
                 getFakeNavControlTarget(focusedWin));
         if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
             return;
         }
-        mTopBar.setVisible(focusedWin == null
-                || focusedWin != getTopControlTarget(focusedWin)
+        mStatusBar.setVisible(focusedWin == null
+                || focusedWin != getStatusControlTarget(focusedWin)
                 || focusedWin.getClientInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
         mNavBar.setVisible(focusedWin == null
                 || focusedWin != getNavControlTarget(focusedWin)
@@ -110,6 +110,10 @@
         mStateController.notifyInsetsChanged();
     }
 
+    boolean isTransient(@InternalInsetsType int type) {
+        return mShowingTransientTypes.indexOf(type) != -1;
+    }
+
     /**
      * @see InsetsStateController#getInsetsForDispatch
      */
@@ -130,8 +134,8 @@
         if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
             return;
         }
-        if (windowState == getTopControlTarget(mFocusedWin)) {
-            mTopBar.setVisible(state.getSource(ITYPE_STATUS_BAR).isVisible());
+        if (windowState == getStatusControlTarget(mFocusedWin)) {
+            mStatusBar.setVisible(state.getSource(ITYPE_STATUS_BAR).isVisible());
         }
         if (windowState == getNavControlTarget(mFocusedWin)) {
             mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
@@ -164,7 +168,8 @@
         }
     }
 
-    private @Nullable InsetsControlTarget getFakeTopControlTarget(@Nullable WindowState focused) {
+    private @Nullable InsetsControlTarget getFakeStatusControlTarget(
+            @Nullable WindowState focused) {
         if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
             return focused;
         }
@@ -178,7 +183,7 @@
         return null;
     }
 
-    private @Nullable InsetsControlTarget getTopControlTarget(@Nullable WindowState focusedWin) {
+    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
         if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
             return mTransientControlTarget;
         }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 69e8fdc..0821873 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -141,9 +141,10 @@
     }
 
     /**
-     * Called when a layout pass has occurred.
+     * The source frame can affect the layout of other windows, so this should be called once the
+     * window gets laid out.
      */
-    void onPostLayout() {
+    void updateSourceFrame() {
         if (mWin == null) {
             return;
         }
@@ -155,6 +156,17 @@
             mTmpRect.inset(mWin.mGivenContentInsets);
         }
         mSource.setFrame(mTmpRect);
+    }
+
+    /**
+     * Called when a layout pass has occurred.
+     */
+    void onPostLayout() {
+        if (mWin == null) {
+            return;
+        }
+
+        updateSourceFrame();
         if (mControl != null) {
             final Rect frame = mWin.getWindowFrames().mFrame;
             if (mControl.setSurfacePosition(frame.left, frame.top)) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 3a0696f..6f81957 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -296,7 +296,7 @@
         boolean requestDismissKeyguard = false;
         for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
              displayNdx >= 0; displayNdx--) {
-            final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
+            final DisplayContent display = mRootActivityContainer.getChildAt(displayNdx);
             final KeyguardDisplayState state = getDisplay(display.mDisplayId);
             state.visibilitiesUpdated(this, display);
             requestDismissKeyguard |= state.mRequestDismissKeyguard;
@@ -420,7 +420,7 @@
     private void updateKeyguardSleepToken() {
         for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
              displayNdx >= 0; displayNdx--) {
-            final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
+            final DisplayContent display = mRootActivityContainer.getChildAt(displayNdx);
             updateKeyguardSleepToken(display.mDisplayId);
         }
     }
@@ -483,7 +483,7 @@
             }
         }
 
-        void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) {
+        void visibilitiesUpdated(KeyguardController controller, DisplayContent display) {
             final boolean lastOccluded = mOccluded;
             final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
             mRequestDismissKeyguard = false;
@@ -530,7 +530,7 @@
          * Only the top non-pinned activity of the focusable stack on each display can control its
          * occlusion state.
          */
-        private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+        private ActivityStack getStackForControllingOccluding(DisplayContent display) {
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 if (stack != null && stack.isFocusableAndVisible()
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index c3bcc74..8cf3dc8 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -223,8 +223,8 @@
     private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
         final ActivityStack stack = task.getStack();
         final int displayId = stack.mDisplayId;
-        final ActivityDisplay display =
-                mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
+        final DisplayContent display =
+                mSupervisor.mRootActivityContainer.getDisplayContent(displayId);
         final DisplayInfo info = new DisplayInfo();
         display.mDisplay.getDisplayInfo(info);
 
@@ -260,7 +260,7 @@
             return;
         }
 
-        final ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay(
+        final DisplayContent display = mSupervisor.mRootActivityContainer.getDisplayContent(
                 persistableParams.mDisplayUniqueId);
         if (display != null) {
             outParams.mPreferredDisplayId =  display.mDisplayId;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e199b2887..71bbb70 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -208,7 +208,7 @@
                 synchronized (mService.mGlobalLock) {
                     // Unfreeze the task list once we touch down in a task
                     final RootActivityContainer rac = mService.mRootActivityContainer;
-                    final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
+                    final DisplayContent dc = rac.getDisplayContent(displayId).mDisplayContent;
                     if (dc.pointWithinAppWindow(x, y)) {
                         final ActivityStack stack = mService.getTopDisplayFocusedStack();
                         final Task topTask = stack != null ? stack.getTopMostTask() : null;
@@ -1317,7 +1317,7 @@
         // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
         final ActivityStack stack = task.getStack();
         if (stack != null) {
-            ActivityDisplay display = stack.getDisplay();
+            DisplayContent display = stack.getDisplay();
             if (display != null && display.isSingleTaskInstance()) {
                 return false;
             }
@@ -1387,7 +1387,7 @@
         }
 
         // Trim tasks that are in stacks that are behind the home stack
-        final ActivityDisplay display = stack.getDisplay();
+        final DisplayContent display = stack.getDisplay();
         return display.getIndexOf(stack) < display.getIndexOf(display.getHomeStack());
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index b398626..0a8e747 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -53,14 +53,14 @@
  * cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
  */
 class RecentsAnimation implements RecentsAnimationCallbacks,
-        ActivityDisplay.OnStackOrderChangedListener {
+        DisplayContent.OnStackOrderChangedListener {
     private static final String TAG = RecentsAnimation.class.getSimpleName();
 
     private final ActivityTaskManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private final ActivityStartController mActivityStartController;
     private final WindowManagerService mWindowManager;
-    private final ActivityDisplay mDefaultDisplay;
+    private final DisplayContent mDefaultDisplay;
     private final Intent mTargetIntent;
     private final ComponentName mRecentsComponent;
     private final int mRecentsUid;
@@ -180,7 +180,7 @@
         ActivityRecord targetActivity = getTargetActivity(targetStack);
         final boolean hasExistingActivity = targetActivity != null;
         if (hasExistingActivity) {
-            final ActivityDisplay display = targetActivity.getDisplay();
+            final DisplayContent display = targetActivity.getDisplay();
             mRestoreTargetBehindStack = display.getStackAbove(targetStack);
             if (mRestoreTargetBehindStack == null) {
                 notifyAnimationCancelBeforeStart(recentsAnimationRunner);
@@ -250,7 +250,7 @@
             mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
                     "startRecentsActivity");
             mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
-                    this, mDefaultDisplay.mDisplayId,
+                    this, mDefaultDisplay.getDisplayId(),
                     mStackSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity);
 
             // If we updated the launch-behind state, update the visibility of the activities after
@@ -351,7 +351,7 @@
                         }
                     } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
                         // Restore the target stack to its previous position
-                        final ActivityDisplay display = targetActivity.getDisplay();
+                        final DisplayContent display = targetActivity.getDisplay();
                         display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack);
                         if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
                             final ActivityStack aboveTargetStack =
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 3aa91d5..d787cbc 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -258,7 +258,7 @@
     private void processCreatedTasks() {
         if (mCreatedTasks.isEmpty()) return;
 
-        ActivityDisplay display = mParent.getDisplay();
+        DisplayContent display = mParent.getDisplay();
         final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
         if (singleTaskInstanceDisplay) {
             display = mParent.mRootActivityContainer.getDefaultDisplay();
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 704a4b7..7dd9790 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -109,7 +109,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
-import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -176,10 +175,10 @@
      * List of displays which contain activities, sorted by z-order.
      * The last entry in the list is the topmost.
      */
-    private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>();
+    private final ArrayList<DisplayContent> mDisplayContents = new ArrayList<>();
 
     /** Reference to default display so we can quickly look it up. */
-    private ActivityDisplay mDefaultDisplay;
+    private DisplayContent mDefaultDisplay;
     private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
 
     /** The current user */
@@ -355,35 +354,35 @@
         final Display[] displays = mDisplayManager.getDisplays();
         for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
             final Display display = displays[displayNdx];
-            final ActivityDisplay activityDisplay = new ActivityDisplay(this, display);
-            if (activityDisplay.mDisplayId == DEFAULT_DISPLAY) {
-                mDefaultDisplay = activityDisplay;
+            final DisplayContent displayContent = new DisplayContent(display, this);
+            if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
+                mDefaultDisplay = displayContent;
             }
-            addChild(activityDisplay, ActivityDisplay.POSITION_TOP);
+            addChild(displayContent, DisplayContent.POSITION_TOP);
         }
         calculateDefaultMinimalSizeOfResizeableTasks();
 
-        final ActivityDisplay defaultDisplay = getDefaultDisplay();
+        final DisplayContent defaultDisplay = getDefaultDisplay();
 
         defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-        positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP);
+        positionChildAt(defaultDisplay, DisplayContent.POSITION_TOP);
     }
 
     // TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display.
-    ActivityDisplay getDefaultDisplay() {
+    DisplayContent getDefaultDisplay() {
         return mDefaultDisplay;
     }
 
     /**
-     * Get an existing instance of {@link ActivityDisplay} that has the given uniqueId. Unique ID is
+     * Get an existing instance of {@link DisplayContent} that has the given uniqueId. Unique ID is
      * defined in {@link DisplayInfo#uniqueId}.
      *
      * @param uniqueId the unique ID of the display
-     * @return the {@link ActivityDisplay} or {@code null} if nothing is found.
+     * @return the {@link DisplayContent} or {@code null} if nothing is found.
      */
-    ActivityDisplay getActivityDisplay(String uniqueId) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+    DisplayContent getDisplayContent(String uniqueId) {
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
             final boolean isValid = display.mDisplay.isValid();
             if (isValid && display.mDisplay.getUniqueId().equals(uniqueId)) {
                 return display;
@@ -393,26 +392,26 @@
         return null;
     }
 
-    // TODO: Look into consolidating with getActivityDisplayOrCreate()
-    ActivityDisplay getActivityDisplay(int displayId) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay activityDisplay = mActivityDisplays.get(i);
-            if (activityDisplay.mDisplayId == displayId) {
-                return activityDisplay;
+    // TODO: Look into consolidating with getDisplayContentOrCreate()
+    DisplayContent getDisplayContent(int displayId) {
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent displayContent = mDisplayContents.get(i);
+            if (displayContent.mDisplayId == displayId) {
+                return displayContent;
             }
         }
         return null;
     }
 
     /**
-     * Get an existing instance of {@link ActivityDisplay} or create new if there is a
+     * Get an existing instance of {@link DisplayContent} or create new if there is a
      * corresponding record in display manager.
      */
-    // TODO: Look into consolidating with getActivityDisplay()
-    @Nullable ActivityDisplay getActivityDisplayOrCreate(int displayId) {
-        ActivityDisplay activityDisplay = getActivityDisplay(displayId);
-        if (activityDisplay != null) {
-            return activityDisplay;
+    // TODO: Look into consolidating with getDisplayContent()
+    @Nullable DisplayContent getDisplayContentOrCreate(int displayId) {
+        DisplayContent displayContent = getDisplayContent(displayId);
+        if (displayContent != null) {
+            return displayContent;
         }
         if (mDisplayManager == null) {
             // The system isn't fully initialized yet.
@@ -424,9 +423,9 @@
             return null;
         }
         // The display hasn't been added to ActivityManager yet, create a new record now.
-        activityDisplay = new ActivityDisplay(this, display);
-        addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM);
-        return activityDisplay;
+        displayContent = new DisplayContent(display, this);
+        addChild(displayContent, DisplayContent.POSITION_BOTTOM);
+        return displayContent;
     }
 
     ActivityRecord getDefaultDisplayHomeActivity() {
@@ -434,21 +433,21 @@
     }
 
     ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
-        return getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
+        return getDisplayContent(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
     }
 
     boolean startHomeOnAllDisplays(int userId, String reason) {
         boolean homeStarted = false;
-        for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
-            final int displayId = mActivityDisplays.get(i).mDisplayId;
+        for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+            final int displayId = mDisplayContents.get(i).mDisplayId;
             homeStarted |= startHomeOnDisplay(userId, reason, displayId);
         }
         return homeStarted;
     }
 
     void startHomeOnEmptyDisplays(String reason) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+            final DisplayContent display = mDisplayContents.get(i);
             if (display.topRunningActivity() == null) {
                 startHomeOnDisplay(mCurrentUser, reason, display.mDisplayId);
             }
@@ -630,7 +629,7 @@
             displayId = DEFAULT_DISPLAY;
         }
 
-        final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity();
+        final ActivityRecord r = getDisplayContent(displayId).getHomeActivity();
         final String myReason = reason + " resumeHomeActivity";
 
         // Only resume home activity if isn't finishing.
@@ -672,7 +671,7 @@
             return false;
         }
 
-        final ActivityDisplay display = getActivityDisplay(displayId);
+        final DisplayContent display = getDisplayContent(displayId);
         if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) {
             // Can't launch home on display that doesn't support system decorations.
             return false;
@@ -772,10 +771,8 @@
 
         if (displayContent != null) {
             // Update the configuration of the activities on the display.
-            // TODO(display-merge): Remove cast
-            return ((ActivityDisplay) displayContent)
-                .updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
-                    null /* result */);
+            return displayContent.updateDisplayOverrideConfigurationLocked(config, starting,
+                    deferResume, null /* result */);
         } else {
             return true;
         }
@@ -789,8 +786,8 @@
         final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
         final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
         // Traverse all displays.
-        for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+            final DisplayContent display = mDisplayContents.get(i);
             // Traverse all stacks on a display.
             for (int j = display.getStackCount() - 1; j >= 0; --j) {
                 final ActivityStack stack = display.getStackAt(j);
@@ -811,8 +808,8 @@
     }
 
     ActivityStack getTopDisplayFocusedStack() {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityStack focusedStack = mActivityDisplays.get(i).getFocusedStack();
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final ActivityStack focusedStack = mDisplayContents.get(i).getFocusedStack();
             if (focusedStack != null) {
                 return focusedStack;
             }
@@ -831,8 +828,8 @@
         }
         // The top focused stack might not have a resumed activity yet - look on all displays in
         // focus order.
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
             final ActivityRecord resumedActivityOnDisplay = display.getResumedActivity();
             if (resumedActivityOnDisplay != null) {
                 return resumedActivityOnDisplay;
@@ -861,8 +858,8 @@
         // previous app if this activity is being hosted by the process that is actually still the
         // foreground.
         WindowProcessController fgApp = null;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 if (isTopDisplayFocusedStack(stack)) {
@@ -889,8 +886,8 @@
     boolean attachApplication(WindowProcessController app) throws RemoteException {
         final String processName = app.mName;
         boolean didSomething = false;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             final ActivityStack stack = display.getFocusedStack();
             if (stack == null) {
                 continue;
@@ -958,8 +955,8 @@
         try {
             mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
             // First the front stacks. In case any are not fullscreen and are in front of home.
-            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-                final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+                final DisplayContent display = mDisplayContents.get(displayNdx);
                 display.ensureActivitiesVisible(starting, configChanges, preserveWindows,
                         notifyClients);
             }
@@ -988,8 +985,8 @@
         mCurrentUser = userId;
 
         mStackSupervisor.mStartingUsers.add(uss);
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.switchUser(userId);
@@ -1036,8 +1033,8 @@
      * @param onTop Indicates whether container should be place on top or on bottom.
      */
     void moveStackToDisplay(int stackId, int displayId, boolean onTop) {
-        final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
-        if (activityDisplay == null) {
+        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+        if (displayContent == null) {
             throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId="
                     + displayId);
         }
@@ -1047,7 +1044,7 @@
                     + stackId);
         }
 
-        final ActivityDisplay currentDisplay = stack.getDisplay();
+        final DisplayContent currentDisplay = stack.getDisplay();
         if (currentDisplay == null) {
             throw new IllegalStateException("moveStackToDisplay: Stack with stack=" + stack
                     + " is not attached to any display.");
@@ -1058,14 +1055,14 @@
                     + " to its current displayId=" + displayId);
         }
 
-        if (activityDisplay.isSingleTaskInstance() && activityDisplay.getStackCount() > 0) {
+        if (displayContent.isSingleTaskInstance() && displayContent.getStackCount() > 0) {
             // We don't allow moving stacks to single instance display that already has a child.
             Slog.e(TAG, "Can not move stack=" + stack
-                    + " to single task instance display=" + activityDisplay);
+                    + " to single task instance display=" + displayContent);
             return;
         }
 
-        stack.reparent(activityDisplay.mDisplayContent, onTop);
+        stack.reparent(displayContent.mDisplayContent, onTop);
         // TODO(multi-display): resize stacks properly if moved from split-screen.
     }
 
@@ -1098,7 +1095,7 @@
             String reason) {
         mService.deferWindowLayout();
 
-        final ActivityDisplay display = r.getActivityStack().getDisplay();
+        final DisplayContent display = r.getActivityStack().getDisplay();
 
         try {
             final Task task = r.getTask();
@@ -1168,8 +1165,8 @@
     }
 
     void executeAppTransitionForAllDisplay() {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             display.mDisplayContent.executeAppTransition();
         }
     }
@@ -1194,7 +1191,7 @@
         mTmpFindTaskResult.clear();
 
         // Looking up task on preferred display first
-        final ActivityDisplay preferredDisplay = getActivityDisplay(preferredDisplayId);
+        final DisplayContent preferredDisplay = getDisplayContent(preferredDisplayId);
         if (preferredDisplay != null) {
             preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult);
             if (mTmpFindTaskResult.mIdealMatch) {
@@ -1202,8 +1199,8 @@
             }
         }
 
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             if (display.mDisplayId == preferredDisplayId) {
                 continue;
             }
@@ -1227,8 +1224,8 @@
     int finishTopCrashedActivities(WindowProcessController app, String reason) {
         Task finishedTask = null;
         ActivityStack focusedStack = getTopDisplayFocusedStack();
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             // It is possible that request to finish activity might also remove its task and stack,
             // so we need to be careful with indexes in the loop and check child count every time.
             for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
@@ -1259,9 +1256,9 @@
             result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
 
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
             boolean resumedOnDisplay = false;
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord topRunningActivity = stack.topRunningActivity();
@@ -1291,7 +1288,7 @@
                 final ActivityStack focusedStack = display.getFocusedStack();
                 if (focusedStack != null) {
                     result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
-                } else if (targetStack == null && !display.hasChild()) {
+                } else if (targetStack == null && display.getStackCount() == 0) {
                     result |= resumeHomeActivity(null /* prev */, "empty-display",
                             display.mDisplayId);
                 }
@@ -1302,9 +1299,9 @@
     }
 
     void applySleepTokens(boolean applyToStacks) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
             // Set the sleeping state of the display.
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             final boolean displayShouldSleep = display.shouldSleep();
             if (displayShouldSleep == display.isSleeping()) {
                 continue;
@@ -1358,8 +1355,8 @@
     }
 
     protected ActivityStack getStack(int stackId) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mActivityDisplays.get(i).getStack(stackId);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final ActivityStack stack = mDisplayContents.get(i).getStack(stackId);
             if (stack != null) {
                 return stack;
             }
@@ -1367,11 +1364,11 @@
         return null;
     }
 
-    /** @see ActivityDisplay#getStack(int, int) */
+    /** @see DisplayContent#getStack(int, int) */
     ActivityStack getStack(int windowingMode, int activityType) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
             final ActivityStack stack =
-                    mActivityDisplays.get(i).getStack(windowingMode, activityType);
+                    mDisplayContents.get(i).getStack(windowingMode, activityType);
             if (stack != null) {
                 return stack;
             }
@@ -1381,7 +1378,7 @@
 
     private ActivityStack getStack(int windowingMode, int activityType,
             int displayId) {
-        ActivityDisplay display = getActivityDisplay(displayId);
+        DisplayContent display = getDisplayContent(displayId);
         if (display == null) {
             return null;
         }
@@ -1390,7 +1387,7 @@
 
     private ActivityManager.StackInfo getStackInfo(ActivityStack stack) {
         final int displayId = stack.mDisplayId;
-        final ActivityDisplay display = getActivityDisplay(displayId);
+        final DisplayContent display = getDisplayContent(displayId);
         ActivityManager.StackInfo info = new ActivityManager.StackInfo();
         stack.getBounds(info.bounds);
         info.displayId = displayId;
@@ -1455,8 +1452,8 @@
     ArrayList<ActivityManager.StackInfo> getAllStackInfos(int displayId) {
         ArrayList<ActivityManager.StackInfo> list = new ArrayList<>();
         if (displayId == INVALID_DISPLAY) {
-            for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
-                final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+                final DisplayContent display = mDisplayContents.get(displayNdx);
                 for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                     final ActivityStack stack = display.getStackAt(stackNdx);
                     list.add(getStackInfo(stack));
@@ -1464,7 +1461,7 @@
             }
             return list;
         }
-        final ActivityDisplay display = getActivityDisplay(displayId);
+        final DisplayContent display = getDisplayContent(displayId);
         if (display == null) {
             return list;
         }
@@ -1493,7 +1490,7 @@
     public void onDisplayAdded(int displayId) {
         if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
-            final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+            final DisplayContent display = getDisplayContentOrCreate(displayId);
             if (display == null) {
                 return;
             }
@@ -1519,12 +1516,12 @@
         }
 
         synchronized (mService.mGlobalLock) {
-            final ActivityDisplay activityDisplay = getActivityDisplay(displayId);
-            if (activityDisplay == null) {
+            final DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent == null) {
                 return;
             }
 
-            activityDisplay.remove();
+            displayContent.remove();
         }
     }
 
@@ -1532,9 +1529,9 @@
     public void onDisplayChanged(int displayId) {
         if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
-            final ActivityDisplay activityDisplay = getActivityDisplay(displayId);
-            if (activityDisplay != null) {
-                activityDisplay.onDisplayChanged();
+            final DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent != null) {
+                displayContent.onDisplayChanged();
             }
         }
     }
@@ -1542,12 +1539,12 @@
     /** Update lists of UIDs that are present on displays and have access to them. */
     void updateUIDsPresentOnDisplay() {
         mDisplayAccessUIDs.clear();
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent displayContent = mDisplayContents.get(displayNdx);
             // Only bother calculating the whitelist for private displays
-            if (activityDisplay.isPrivate()) {
+            if (displayContent.isPrivate()) {
                 mDisplayAccessUIDs.append(
-                        activityDisplay.mDisplayId, activityDisplay.getPresentUIDs());
+                        displayContent.mDisplayId, displayContent.getPresentUIDs());
             }
         }
         // Store updated lists in DisplayManager. Callers from outside of AM should get them there.
@@ -1555,7 +1552,7 @@
     }
 
     ActivityStack findStackBehind(ActivityStack stack) {
-        final ActivityDisplay display = getActivityDisplay(stack.mDisplayId);
+        final DisplayContent display = getDisplayContent(stack.mDisplayId);
         if (display != null) {
             for (int i = display.getStackCount() - 1; i >= 0; i--) {
                 if (display.getStackAt(i) == stack && i > 0) {
@@ -1569,12 +1566,12 @@
 
     @Override
     protected int getChildCount() {
-        return mActivityDisplays.size();
+        return mDisplayContents.size();
     }
 
     @Override
-    protected ActivityDisplay getChildAt(int index) {
-        return mActivityDisplays.get(index);
+    protected DisplayContent getChildAt(int index) {
+        return mDisplayContents.get(index);
     }
 
     @Override
@@ -1592,61 +1589,59 @@
 
     /** Change the z-order of the given display. */
     private void positionChildAt(DisplayContent display, int position) {
-        if (position >= mActivityDisplays.size()) {
-            position = mActivityDisplays.size() - 1;
+        if (position >= mDisplayContents.size()) {
+            position = mDisplayContents.size() - 1;
         } else if (position < 0) {
             position = 0;
         }
 
-        // TODO(display-merge): Remove cast
-        final ActivityDisplay activityDisplay = (ActivityDisplay) display;
-        if (mActivityDisplays.isEmpty()) {
-            mActivityDisplays.add(activityDisplay);
-        } else if (mActivityDisplays.get(position) != display) {
-            mActivityDisplays.remove(display);
-            mActivityDisplays.add(position, activityDisplay);
+        if (mDisplayContents.isEmpty()) {
+            mDisplayContents.add(display);
+        } else if (mDisplayContents.get(position) != display) {
+            mDisplayContents.remove(display);
+            mDisplayContents.add(position, display);
         }
         mStackSupervisor.updateTopResumedActivityIfNeeded();
     }
 
     @VisibleForTesting
-    void addChild(ActivityDisplay activityDisplay, int position) {
-        positionChildAt(activityDisplay, position);
-        mRootWindowContainer.positionChildAt(position, activityDisplay.mDisplayContent);
+    void addChild(DisplayContent displayContent, int position) {
+        positionChildAt(displayContent, position);
+        mRootWindowContainer.positionChildAt(position, displayContent);
     }
 
-    void removeChild(ActivityDisplay activityDisplay) {
-        // The caller must tell the controller of {@link ActivityDisplay} to release its container
-        // {@link DisplayContent}. That is done in {@link ActivityDisplay#releaseSelfIfNeeded}).
-        mActivityDisplays.remove(activityDisplay);
+    void removeChild(DisplayContent displayContent) {
+        // The caller must tell the controller of {@link DisplayContent} to release its container
+        // {@link DisplayContent}. That is done in {@link DisplayContent#releaseSelfIfNeeded}).
+        mDisplayContents.remove(displayContent);
     }
 
     Configuration getDisplayOverrideConfiguration(int displayId) {
-        final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
-        if (activityDisplay == null) {
+        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+        if (displayContent == null) {
             throw new IllegalArgumentException("No display found with id: " + displayId);
         }
 
-        return activityDisplay.getRequestedOverrideConfiguration();
+        return displayContent.getRequestedOverrideConfiguration();
     }
 
     void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) {
-        final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
-        if (activityDisplay == null) {
+        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+        if (displayContent == null) {
             throw new IllegalArgumentException("No display found with id: " + displayId);
         }
 
-        activityDisplay.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+        displayContent.onRequestedOverrideConfigurationChanged(overrideConfiguration);
     }
 
     void prepareForShutdown() {
-        for (int i = 0; i < mActivityDisplays.size(); i++) {
-            createSleepToken("shutdown", mActivityDisplays.get(i).mDisplayId);
+        for (int i = 0; i < mDisplayContents.size(); i++) {
+            createSleepToken("shutdown", mDisplayContents.get(i).mDisplayId);
         }
     }
 
     ActivityTaskManagerInternal.SleepToken createSleepToken(String tag, int displayId) {
-        final ActivityDisplay display = getActivityDisplay(displayId);
+        final DisplayContent display = getDisplayContent(displayId);
         if (display == null) {
             throw new IllegalArgumentException("Invalid display: " + displayId);
         }
@@ -1660,7 +1655,7 @@
     private void removeSleepToken(SleepTokenImpl token) {
         mSleepTokens.remove(token);
 
-        final ActivityDisplay display = getActivityDisplay(token.mDisplayId);
+        final DisplayContent display = getDisplayContent(token.mDisplayId);
         if (display != null) {
             display.mAllSleepTokens.remove(token);
             if (display.mAllSleepTokens.isEmpty()) {
@@ -1717,8 +1712,8 @@
     }
 
     void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.scheduleDestroyActivities(app, reason);
@@ -1730,8 +1725,8 @@
     // successfully put to sleep.
     boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
         boolean allSleep = true;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 // Stacks and activities could be removed while putting activities to sleep if
                 // the app process was gone. This prevents us getting exception by accessing an
@@ -1801,8 +1796,8 @@
     }
 
     boolean hasAwakeDisplay() {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             if (!display.shouldSleep()) {
                 return true;
             }
@@ -1878,7 +1873,7 @@
                     return stack;
                 }
             }
-            final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+            final DisplayContent display = getDisplayContentOrCreate(displayId);
             if (display != null) {
                 stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
                 if (stack != null) {
@@ -1890,7 +1885,7 @@
         // Give preference to the stack and display of the input task and activity if they match the
         // mode we want to launch into.
         stack = null;
-        ActivityDisplay display = null;
+        DisplayContent display = null;
         if (candidateTask != null) {
             stack = candidateTask.getStack();
         }
@@ -1948,8 +1943,8 @@
     private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
             @Nullable Task candidateTask, @Nullable ActivityOptions options,
             @Nullable LaunchParamsController.LaunchParams launchParams) {
-        final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
-        if (activityDisplay == null) {
+        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
+        if (displayContent == null) {
             throw new IllegalArgumentException(
                     "Display with displayId=" + displayId + " not found.");
         }
@@ -1978,12 +1973,12 @@
             windowingMode = options != null ? options.getLaunchWindowingMode()
                     : r.getWindowingMode();
         }
-        windowingMode = activityDisplay.validateWindowingMode(windowingMode, r, candidateTask,
+        windowingMode = displayContent.validateWindowingMode(windowingMode, r, candidateTask,
                 r.getActivityType());
 
         // Return the topmost valid stack on the display.
-        for (int i = activityDisplay.getStackCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = activityDisplay.getStackAt(i);
+        for (int i = displayContent.getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = displayContent.getStackAt(i);
             if (isValidLaunchStack(stack, r, windowingMode)) {
                 return stack;
             }
@@ -1994,7 +1989,7 @@
             final int activityType =
                     options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
                             ? options.getLaunchActivityType() : r.getActivityType();
-            return activityDisplay.createStack(windowingMode, activityType, true /*onTop*/);
+            return displayContent.createStack(windowingMode, activityType, true /*onTop*/);
         }
 
         return null;
@@ -2056,11 +2051,11 @@
     ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus,
             boolean ignoreCurrent) {
         // First look for next focusable stack on the same display
-        ActivityDisplay preferredDisplay = currentFocus.getDisplay();
+        DisplayContent preferredDisplay = currentFocus.getDisplay();
         if (preferredDisplay == null) {
             // Stack is currently detached because it is being removed. Use the previous display it
             // was on.
-            preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId);
+            preferredDisplay = getDisplayContent(currentFocus.mPrevDisplayId);
         }
         final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack(
                 currentFocus, ignoreCurrent);
@@ -2075,8 +2070,8 @@
         }
 
         // Now look through all displays
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
             if (display == preferredDisplay) {
                 // We've already checked this one
                 continue;
@@ -2102,8 +2097,8 @@
      * @return Next valid {@link ActivityStack}, null if not found.
      */
     ActivityStack getNextValidLaunchStack(@NonNull ActivityRecord r, int currentFocus) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
             if (display.mDisplayId == currentFocus) {
                 continue;
             }
@@ -2118,8 +2113,8 @@
 
     boolean handleAppDied(WindowProcessController app) {
         boolean hasVisibleActivities = false;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 hasVisibleActivities |= stack.handleAppDiedLocked(app);
@@ -2231,8 +2226,8 @@
     }
 
     void finishVoiceTask(IVoiceInteractionSession session) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             final int numStacks = display.getStackCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
@@ -2246,20 +2241,20 @@
      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
      */
     void removeStacksInWindowingModes(int... windowingModes) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            mActivityDisplays.get(i).removeStacksInWindowingModes(windowingModes);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            mDisplayContents.get(i).removeStacksInWindowingModes(windowingModes);
         }
     }
 
     void removeStacksWithActivityTypes(int... activityTypes) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            mActivityDisplays.get(i).removeStacksWithActivityTypes(activityTypes);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            mDisplayContents.get(i).removeStacksWithActivityTypes(activityTypes);
         }
     }
 
     ActivityRecord topRunningActivity() {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityRecord topActivity = mActivityDisplays.get(i).topRunningActivity();
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final ActivityRecord topActivity = mDisplayContents.get(i).topRunningActivity();
             if (topActivity != null) {
                 return topActivity;
             }
@@ -2268,9 +2263,9 @@
     }
 
     boolean allResumedActivitiesIdle() {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
             // TODO(b/117135575): Check resumed activities on all visible stacks.
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             if (display.isSleeping()) {
                 // No resumed activities while display is sleeping.
                 continue;
@@ -2298,8 +2293,8 @@
 
     boolean allResumedActivitiesVisible() {
         boolean foundResumed = false;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.getResumedActivity();
@@ -2316,8 +2311,8 @@
 
     boolean allPausedActivitiesComplete() {
         boolean pausing = true;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
@@ -2381,8 +2376,8 @@
     }
 
     void cancelInitializingActivities() {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.cancelInitializingActivities();
@@ -2467,9 +2462,9 @@
     }
 
     ActivityRecord isInAnyStack(IBinder token) {
-        int numDisplays = mActivityDisplays.size();
+        int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.isInStackLocked(token);
@@ -2503,9 +2498,9 @@
             // activity on all displays, or if there are no resumed activities in the system.
             boolean noResumedActivities = true;
             boolean allFocusedProcessesDiffer = true;
-            for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
-                final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
-                final ActivityRecord resumedActivity = activityDisplay.getResumedActivity();
+            for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+                final DisplayContent displayContent = mDisplayContents.get(displayNdx);
+                final ActivityRecord resumedActivity = displayContent.getResumedActivity();
                 final WindowProcessController resumedActivityProcess =
                         resumedActivity == null ? null : resumedActivity.app;
 
@@ -2550,9 +2545,9 @@
             return getTopDisplayFocusedStack().getDumpActivitiesLocked(name);
         } else {
             ArrayList<ActivityRecord> activities = new ArrayList<>();
-            int numDisplays = mActivityDisplays.size();
+            int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+                final DisplayContent display = mDisplayContents.get(displayNdx);
                 for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                     final ActivityStack stack = display.getStackAt(stackNdx);
                     if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
@@ -2567,9 +2562,9 @@
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix);
         pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
-            display.dump(pw, prefix);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
+            display.dump(pw, prefix, true /* dumpAll */);
         }
     }
 
@@ -2579,17 +2574,17 @@
      */
     void dumpDisplayConfigs(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.println("Display override configurations:");
-        final int displayCount = mActivityDisplays.size();
+        final int displayCount = mDisplayContents.size();
         for (int i = 0; i < displayCount; i++) {
-            final ActivityDisplay activityDisplay = mActivityDisplays.get(i);
-            pw.print(prefix); pw.print("  "); pw.print(activityDisplay.mDisplayId); pw.print(": ");
-            pw.println(activityDisplay.getRequestedOverrideConfiguration());
+            final DisplayContent displayContent = mDisplayContents.get(i);
+            pw.print(prefix); pw.print("  "); pw.print(displayContent.mDisplayId); pw.print(": ");
+            pw.println(displayContent.getRequestedOverrideConfiguration());
         }
     }
 
     public void dumpDisplays(PrintWriter pw) {
-        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final ActivityDisplay display = mActivityDisplays.get(i);
+        for (int i = mDisplayContents.size() - 1; i >= 0; --i) {
+            final DisplayContent display = mDisplayContents.get(i);
             pw.print("[id:" + display.mDisplayId + " stacks:");
             display.dumpStacks(pw);
             pw.print("]");
@@ -2600,18 +2595,18 @@
             String dumpPackage) {
         boolean printed = false;
         boolean needSep = false;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
-            pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            DisplayContent displayContent = mDisplayContents.get(displayNdx);
+            pw.print("Display #"); pw.print(displayContent.mDisplayId);
             pw.println(" (activities from top to bottom):");
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+            final DisplayContent display = mDisplayContents.get(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
                 pw.println();
                 printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
                 needSep = printed;
             }
-            printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep,
+            printThisActivity(pw, displayContent.getResumedActivity(), dumpPackage, needSep,
                     " ResumedActivity:");
         }
 
@@ -2632,9 +2627,9 @@
             @WindowTraceLogLevel int logLevel) {
         final long token = proto.start(fieldId);
         super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
-        for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
-            final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
-            activityDisplay.dumpDebug(proto, DISPLAYS, logLevel);
+        for (int displayNdx = 0; displayNdx < mDisplayContents.size(); ++displayNdx) {
+            final DisplayContent displayContent = mDisplayContents.get(displayNdx);
+            displayContent.dumpDebug(proto, DISPLAYS, logLevel);
         }
         mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
         // TODO(b/111541062): Update tests to look for resumed activities on all displays
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
new file mode 100644
index 0000000..9732637
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.IWindow;
+import android.view.SurfaceControl;
+
+/**
+ * Represents a piece of the hierarchy under which a client Shell can manage sub-windows.
+ */
+public class ShellRoot {
+    private static final String TAG = "ShellRoot";
+    private final DisplayContent mDisplayContent;
+    private IWindow mClient;
+    private WindowToken mToken;
+    private final IBinder.DeathRecipient mDeathRecipient;
+    private SurfaceControl mSurfaceControl = null;
+
+    ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, final int windowType) {
+        mDisplayContent = dc;
+        mDeathRecipient = () -> mDisplayContent.removeShellRoot(windowType);
+        try {
+            client.asBinder().linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to add shell root for layer " + windowType + " on display "
+                    + dc.getDisplayId(), e);
+            return;
+        }
+        mClient = client;
+        mToken = new WindowToken(
+                dc.mWmService, client.asBinder(), windowType, true, dc, true, false);
+        mSurfaceControl = mToken.makeChildSurface(null)
+                .setContainerLayer().setName("Shell Root Leash " + dc.getDisplayId()).build();
+        mToken.getPendingTransaction().show(mSurfaceControl);
+    }
+
+    void clear() {
+        if (mClient != null) {
+            mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
+            mClient = null;
+        }
+        if (mToken != null) {
+            mToken.removeImmediately();
+            mToken = null;
+        }
+    }
+
+    SurfaceControl getSurfaceControl() {
+        return mSurfaceControl;
+    }
+
+    IWindow getClient() {
+        return mClient;
+    }
+}
+
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0e07e52..1b2274a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -135,7 +135,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
@@ -1583,8 +1582,8 @@
         if (!inPinnedWindowingMode() && mStack != null) {
             final int defaultMinSizeDp =
                     mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
-            final ActivityDisplay display =
-                    mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
+            final DisplayContent display =
+                    mAtmService.mRootActivityContainer.getDisplayContent(mStack.mDisplayId);
             final float density =
                     (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
             final int defaultMinSize = (int) (defaultMinSizeDp * density);
@@ -1995,7 +1994,7 @@
                     ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
             final Rect parentBounds =
                     new Rect(newParentConfig.windowConfiguration.getBounds());
-            final ActivityDisplay display = mStack.getDisplay();
+            final DisplayContent display = mStack.getDisplay();
             if (display != null && display.mDisplayContent != null) {
                 // If a freeform window moves below system bar, there is no way to move it again
                 // by touch. Because its caption is covered by system bar. So we exclude them
@@ -2188,7 +2187,7 @@
         final ActivityStack prevStack = getTaskStack();
         final boolean wasTopFocusedStack =
                 mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
-        final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
+        final DisplayContent prevStackDisplay = prevStack.getDisplay();
 
         position = stack.findPositionForTask(this, position, showForAllUsers());
 
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 9d19cfe..4de61f0 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -137,7 +137,7 @@
         // STEP 1: Determine the display to launch the activity/task.
         final int displayId = getPreferredLaunchDisplay(task, options, source, currentParams);
         outParams.mPreferredDisplayId = displayId;
-        ActivityDisplay display = mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
+        DisplayContent display = mSupervisor.mRootActivityContainer.getDisplayContent(displayId);
         if (DEBUG) {
             appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
                     + display.getWindowingMode());
@@ -282,7 +282,7 @@
             if (source != null && source.inFreeformWindowingMode()
                     && resolvedMode == WINDOWING_MODE_FREEFORM
                     && outParams.mBounds.isEmpty()
-                    && source.getDisplayId() == display.mDisplayId) {
+                    && source.getDisplayId() == display.getDisplayId()) {
                 // Set bounds to be not very far from source activity.
                 cascadeBounds(source.getConfiguration().windowConfiguration.getBounds(),
                         display, outParams.mBounds);
@@ -333,17 +333,17 @@
         }
 
         if (displayId != INVALID_DISPLAY
-                && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) == null) {
+                && mSupervisor.mRootActivityContainer.getDisplayContent(displayId) == null) {
             displayId = currentParams.mPreferredDisplayId;
         }
         displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
 
         return (displayId != INVALID_DISPLAY
-                && mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) != null)
+                && mSupervisor.mRootActivityContainer.getDisplayContent(displayId) != null)
                 ? displayId : DEFAULT_DISPLAY;
     }
 
-    private boolean canInheritWindowingModeFromSource(@NonNull ActivityDisplay display,
+    private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
             @Nullable ActivityRecord source) {
         if (source == null) {
             return false;
@@ -365,10 +365,10 @@
         // Only inherit windowing mode if both source and target activities are on the same display.
         // Otherwise we may have unintended freeform windows showing up if an activity in freeform
         // window launches an activity on a fullscreen display by specifying display ID.
-        return display.mDisplayId == source.getDisplayId();
+        return display.getDisplayId() == source.getDisplayId();
     }
 
-    private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display, int launchMode) {
+    private boolean canApplyFreeformWindowPolicy(@NonNull DisplayContent display, int launchMode) {
         return mSupervisor.mService.mSupportsFreeformWindowManagement
                 && (display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM);
     }
@@ -378,7 +378,7 @@
                 && launchMode == WINDOWING_MODE_PINNED;
     }
 
-    private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+    private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root,
             @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
         final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
         final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
@@ -488,7 +488,7 @@
         return orientation;
     }
 
-    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull DisplayContent display,
             @NonNull Rect outBounds) {
         outBounds.set(srcBounds);
         float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
@@ -500,7 +500,7 @@
         outBounds.offset(dx, dy);
     }
 
-    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull DisplayContent display,
             @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
             @NonNull Rect inOutBounds) {
         if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
@@ -567,7 +567,7 @@
         }
     }
 
-    private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+    private int resolveOrientation(@NonNull ActivityRecord root, @NonNull DisplayContent display,
             @NonNull Rect bounds) {
         int orientation = resolveOrientation(root);
 
@@ -593,7 +593,7 @@
         return orientation;
     }
 
-    private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+    private void getDefaultFreeformSize(@NonNull DisplayContent display,
             @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
         // Default size, which is letterboxing/pillarboxing in display. That's to say the large
         // dimension of default size is the small dimension of display size, and the small dimension
@@ -637,7 +637,7 @@
      * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
      * centers at its center or display's app bounds center if inOutBounds is empty.
      */
-    private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+    private void centerBounds(@NonNull DisplayContent display, int width, int height,
             @NonNull Rect inOutBounds) {
         if (inOutBounds.isEmpty()) {
             inOutBounds.set(display.mDisplayContent.mDisplayFrames.mStable);
@@ -647,7 +647,7 @@
         inOutBounds.set(left, top, left + width, top + height);
     }
 
-    private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+    private void adjustBoundsToFitInDisplay(@NonNull DisplayContent display,
             @NonNull Rect inOutBounds) {
         final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable;
 
@@ -702,7 +702,7 @@
      * @param display the display which tasks are to check
      * @param inOutBounds the bounds used to input initial bounds and output result bounds
      */
-    private void adjustBoundsToAvoidConflictInDisplay(@NonNull ActivityDisplay display,
+    private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
             @NonNull Rect inOutBounds) {
         final List<Rect> taskBoundsToCheck = new ArrayList<>();
         for (int i = 0; i < display.getStackCount(); ++i) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 5cbab5d..7b0d841 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -109,7 +109,7 @@
         removeRunningEntry(taskId);
     }
 
-    private void removeRunningEntry(int taskId) {
+    void removeRunningEntry(int taskId) {
         final CacheEntry entry = mRunningCache.get(taskId);
         if (entry != null) {
             mAppTaskMap.remove(entry.topApp);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index c1a36c4..dee9e9f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -171,22 +171,30 @@
     }
 
     void snapshotTasks(ArraySet<Task> tasks) {
+        snapshotTasks(mTmpTasks, false /* allowSnapshotHome */);
+    }
+
+    private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task task = tasks.valueAt(i);
-            final int mode = getSnapshotMode(task);
             final TaskSnapshot snapshot;
-            switch (mode) {
-                case SNAPSHOT_MODE_NONE:
-                    continue;
-                case SNAPSHOT_MODE_APP_THEME:
-                    snapshot = drawAppThemeSnapshot(task);
-                    break;
-                case SNAPSHOT_MODE_REAL:
-                    snapshot = snapshotTask(task);
-                    break;
-                default:
-                    snapshot = null;
-                    break;
+            final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+            if (snapshotHome) {
+                snapshot = snapshotTask(task);
+            } else {
+                switch (getSnapshotMode(task)) {
+                    case SNAPSHOT_MODE_NONE:
+                        continue;
+                    case SNAPSHOT_MODE_APP_THEME:
+                        snapshot = drawAppThemeSnapshot(task);
+                        break;
+                    case SNAPSHOT_MODE_REAL:
+                        snapshot = snapshotTask(task);
+                        break;
+                    default:
+                        snapshot = null;
+                        break;
+                }
             }
             if (snapshot != null) {
                 final GraphicBuffer buffer = snapshot.getSnapshot();
@@ -196,8 +204,11 @@
                             + buffer.getHeight());
                 } else {
                     mCache.putSnapshot(task, snapshot);
-                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
-                    task.onSnapshotChanged(snapshot);
+                    // Don't persist or notify the change for the temporal snapshot.
+                    if (!snapshotHome) {
+                        mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                        task.onSnapshotChanged(snapshot);
+                    }
                 }
             }
         }
@@ -403,7 +414,7 @@
         final LayoutParams attrs = mainWindow.getAttrs();
         final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(),
-                mFullSnapshotScale);
+                mFullSnapshotScale, mainWindow.getClientInsetsState());
         final int width = (int) (task.getBounds().width() * mFullSnapshotScale);
         final int height = (int) (task.getBounds().height() * mFullSnapshotScale);
 
@@ -450,6 +461,10 @@
         mPersister.onTaskRemovedFromRecents(taskId, userId);
     }
 
+    void removeSnapshotCache(int taskId) {
+        mCache.removeRunningEntry(taskId);
+    }
+
     /**
      * See {@link TaskSnapshotPersister#removeObsoleteFiles}
      */
@@ -485,7 +500,9 @@
                             mTmpTasks.add(task);
                         }
                     });
-                    snapshotTasks(mTmpTasks);
+                    // Allow taking snapshot of home when turning screen off to reduce the delay of
+                    // unlocking/waking to home.
+                    snapshotTasks(mTmpTasks, true /* allowSnapshotHome */);
                 }
             } finally {
                 listener.onScreenOff();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index b3750e9..1484d6a 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -71,6 +71,7 @@
 import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -154,6 +155,7 @@
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
         final TaskDescription taskDescription = new TaskDescription();
         taskDescription.setBackgroundColor(WHITE);
+        final WindowState topFullscreenWindow;
         final int sysUiVis;
         final int windowFlags;
         final int windowPrivateFlags;
@@ -173,7 +175,7 @@
                         + task);
                 return null;
             }
-            final WindowState topFullscreenWindow = topFullscreenActivity.getTopFullscreenWindow();
+            topFullscreenWindow = topFullscreenActivity.getTopFullscreenWindow();
             if (mainWindow == null || topFullscreenWindow == null) {
                 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
                         + activity);
@@ -220,7 +222,7 @@
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
                 surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
                 windowFlags, windowPrivateFlags, taskBounds,
-                currentOrientation);
+                currentOrientation, topFullscreenWindow.getClientInsetsState());
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -238,7 +240,7 @@
     TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
             TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
             int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
-            int currentOrientation) {
+            int currentOrientation, InsetsState insetsState) {
         mService = service;
         mSurface = service.mSurfaceFactory.get();
         mHandler = new Handler(mService.mH.getLooper());
@@ -251,7 +253,7 @@
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
         mTaskBounds = taskBounds;
         mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
-                windowPrivateFlags, sysUiVis, taskDescription, 1f);
+                windowPrivateFlags, sysUiVis, taskDescription, 1f, insetsState);
         mStatusBarColor = taskDescription.getStatusBarColor();
         mOrientationOnCreation = currentOrientation;
         mTransaction = mService.mTransactionFactory.get();
@@ -502,9 +504,10 @@
         private final int mWindowPrivateFlags;
         private final int mSysUiVis;
         private final float mScale;
+        private final InsetsState mInsetsState;
 
         SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int sysUiVis,
-                TaskDescription taskDescription, float scale) {
+                TaskDescription taskDescription, float scale, InsetsState insetsState) {
             mWindowFlags = windowFlags;
             mWindowPrivateFlags = windowPrivateFlags;
             mSysUiVis = sysUiVis;
@@ -524,6 +527,7 @@
                             && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
             mStatusBarPaint.setColor(mStatusBarColor);
             mNavigationBarPaint.setColor(mNavigationBarColor);
+            mInsetsState = insetsState;
         }
 
         void setInsets(Rect contentInsets, Rect stableInsets) {
@@ -534,8 +538,11 @@
         int getStatusBarColorViewHeight() {
             final boolean forceBarBackground =
                     (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mSysUiVis, mStatusBarColor, mWindowFlags, forceBarBackground)) {
+            if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
+                    ? STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                            mSysUiVis, mStatusBarColor, mWindowFlags, forceBarBackground)
+                    : STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                            mInsetsState, mStatusBarColor, mWindowFlags, forceBarBackground)) {
                 return (int) (getColorViewTopInset(mStableInsets.top, mContentInsets.top) * mScale);
             } else {
                 return 0;
@@ -545,8 +552,11 @@
         private boolean isNavigationBarColorViewVisible() {
             final boolean forceBarBackground =
                     (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mSysUiVis, mNavigationBarColor, mWindowFlags, forceBarBackground);
+            return ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
+                    ? NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                            mSysUiVis, mNavigationBarColor, mWindowFlags, forceBarBackground)
+                    : NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                            mInsetsState, mNavigationBarColor, mWindowFlags, forceBarBackground);
         }
 
         void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 0490bac..97186b4 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -207,6 +207,7 @@
         return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
     }
 
+    // TODO(b/118118435): Remove after migration.
     /**
      * Calculate the insets for the type
      * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index 10c8ef0..74d5c04 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -19,6 +19,8 @@
 import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.provider.AndroidDeviceConfig;
 import android.provider.DeviceConfig;
 
@@ -72,8 +74,8 @@
     WindowManagerConstants(WindowManagerGlobalLock globalLock,
             Runnable updateSystemGestureExclusionCallback,
             DeviceConfigInterface deviceConfig) {
-        mGlobalLock = globalLock;
-        mUpdateSystemGestureExclusionCallback = updateSystemGestureExclusionCallback;
+        mGlobalLock = checkNotNull(globalLock);
+        mUpdateSystemGestureExclusionCallback = checkNotNull(updateSystemGestureExclusionCallback);
         mDeviceConfig = deviceConfig;
         mListenerAndroid = this::onAndroidPropertiesChanged;
         mListenerWindowManager = this::onWindowPropertiesChanged;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1bd745..acaaed9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -79,7 +79,6 @@
 import static com.android.server.LockGuard.INDEX_WINDOW;
 import static com.android.server.LockGuard.installLock;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -406,8 +405,7 @@
 
     private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
 
-    final WindowManagerConstants mConstants = new WindowManagerConstants(this,
-            DeviceConfigInterface.REAL);
+    final WindowManagerConstants mConstants;
 
     final WindowTracing mWindowTracing;
 
@@ -1233,6 +1231,7 @@
 
         mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
 
+        mConstants = new WindowManagerConstants(this, DeviceConfigInterface.REAL);
         mConstants.start(new HandlerExecutor(mH));
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
@@ -1722,7 +1721,7 @@
             }
         }
 
-        return mAtmService.mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+        return mAtmService.mRootActivityContainer.getDisplayContentOrCreate(displayId);
     }
 
     private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
@@ -3712,6 +3711,26 @@
     }
 
     @Override
+    public SurfaceControl addShellRoot(int displayId, IWindow client, int windowType) {
+        if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+        }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
+                if (dc == null) {
+                    return null;
+                }
+                return dc.addShellRoot(client, windowType);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public int watchRotation(IRotationWatcher watcher, int displayId) {
         final DisplayContent displayContent;
         synchronized (mGlobalLock) {
@@ -7630,7 +7649,11 @@
             return;
         }
 
-        handleDisplayFocusChange(touchedWindow);
+        final DisplayContent displayContent = touchedWindow.getDisplayContent();
+        if (!displayContent.isOnTop()) {
+            displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+                    true /* includingParents */);
+        }
         handleTaskFocusChange(touchedWindow.getTask());
     }
 
@@ -7653,29 +7676,6 @@
         }
     }
 
-    private void handleDisplayFocusChange(WindowState window) {
-        final DisplayContent displayContent = window.getDisplayContent();
-        if (displayContent == null) {
-            return;
-        }
-
-        final WindowContainer parent = displayContent.getParent();
-        if (parent != null && parent.getTopChild() != displayContent) {
-            parent.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
-                    true /* includingParents */);
-            // For compatibility, only the topmost activity is allowed to be resumed for pre-Q
-            // app. Ensure the topmost activities are resumed whenever a display is moved to top.
-            // TODO(b/123761773): Investigate whether we can move this into
-            // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is risky
-            // to do so because it seems possible to resume activities as part of a larger
-            // transaction and it's too early to resume based on current order when performing
-            // updateTopResumedActivityIfNeeded().
-            // TODO(display-merge): Remove cast
-            ((ActivityDisplay) displayContent).ensureActivitiesVisible(null /* starting */,
-                    0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
-        }
-    }
-
     /**
      * Assigns an InputChannel to a SurfaceControl and configures it to receive
      * touch input according to it's on-screen geometry.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index ddf8e9b..1a41006 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -575,14 +575,14 @@
             return true;
         }
 
-        final ActivityDisplay display = activity.getDisplay();
+        final DisplayContent display = activity.getDisplay();
         if (display == null) {
             // No need to update if the activity hasn't attach to any display.
             return false;
         }
 
         boolean canUpdate = false;
-        final ActivityDisplay topDisplay =
+        final DisplayContent topDisplay =
                 mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
         // Update the topmost activity if current top activity is
         // - not on any display OR
@@ -938,15 +938,15 @@
         mAtm.mH.sendMessage(m);
     }
 
-    void registerDisplayConfigurationListenerLocked(ActivityDisplay activityDisplay) {
-        if (activityDisplay == null) {
+    void registerDisplayConfigurationListenerLocked(DisplayContent displayContent) {
+        if (displayContent == null) {
             return;
         }
         // A process can only register to one display to listener to the override configuration
         // change. Unregister existing listener if it has one before register the new one.
         unregisterDisplayConfigurationListenerLocked();
-        mDisplayId = activityDisplay.mDisplayId;
-        activityDisplay.registerConfigurationChangeListener(this);
+        mDisplayId = displayContent.mDisplayId;
+        displayContent.registerConfigurationChangeListener(this);
     }
 
     @VisibleForTesting
@@ -954,10 +954,10 @@
         if (mDisplayId == INVALID_DISPLAY) {
             return;
         }
-        final ActivityDisplay activityDisplay =
-                mAtm.mRootActivityContainer.getActivityDisplay(mDisplayId);
-        if (activityDisplay != null) {
-            activityDisplay.unregisterConfigurationChangeListener(this);
+        final DisplayContent displayContent =
+                mAtm.mRootActivityContainer.getDisplayContent(mDisplayId);
+        if (displayContent != null) {
+            displayContent.unregisterConfigurationChangeListener(this);
         }
         mDisplayId = INVALID_DISPLAY;
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5b7f36d..eab8d05 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2611,7 +2611,7 @@
         final boolean canReceiveKeys = isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
-                && (mActivityRecord == null || mActivityRecord.windowsAreFocusable())
+                && (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
                 && !cantReceiveTouchInput();
         if (!canReceiveKeys) {
             return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eb1753b..078bab4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7440,7 +7440,7 @@
     }
 
     /**
-     * Returns whether or auto time is used on the device or not.
+     * Returns whether auto time is used on the device or not.
      */
     @Override
     public boolean getAutoTime(ComponentName who) {
@@ -7453,6 +7453,42 @@
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
     }
 
+    /**
+     * Set whether auto time zone is enabled on the device.
+     */
+    @Override
+    public void setAutoTimeZone(ComponentName who, boolean enabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        // TODO (b/145286957) Refactor security checks
+        enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+        mInjector.binderWithCleanCallingIdentity(() ->
+                mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
+
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
+                .setAdmin(who)
+                .setBoolean(enabled)
+                .write();
+    }
+
+    /**
+     * Returns whether auto time zone is used on the device or not.
+     */
+    @Override
+    public boolean getAutoTimeZone(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+        return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
+    }
+
     @Override
     public void setForceEphemeralUsers(ComponentName who, boolean forceEphemeralUsers) {
         if (!mHasFeature) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6e29b63..401a094 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -495,6 +495,9 @@
             // Initialize the system context.
             createSystemContext();
 
+            // Call per-process mainline module initialization.
+            ActivityThread.initializeMainlineModules();
+
             // Create the system service manager.
             mSystemServiceManager = new SystemServiceManager(mSystemContext);
             mSystemServiceManager.setStartInfo(mRuntimeRestart,
diff --git a/services/tests/servicestests/res/xml/usertypes_test_eraseArray.xml b/services/tests/servicestests/res/xml/usertypes_test_eraseArray.xml
new file mode 100644
index 0000000..02ac48e
--- /dev/null
+++ b/services/tests/servicestests/res/xml/usertypes_test_eraseArray.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<user-types>
+    <profile-type
+        name='android.test'
+        max-allowed-per-parent='2' >
+        <badge-colors>
+        </badge-colors>
+        <default-restrictions />
+    </profile-type>
+</user-types>
\ No newline at end of file
diff --git a/services/tests/servicestests/res/xml/usertypes_test_full.xml b/services/tests/servicestests/res/xml/usertypes_test_full.xml
new file mode 100644
index 0000000..a281dca
--- /dev/null
+++ b/services/tests/servicestests/res/xml/usertypes_test_full.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<user-types>
+    <full-type
+        name='android.test.1'
+        max-allowed-per-parent='12' >
+        <default-restrictions no_remove_user='true' no_bluetooth='true' />
+        <badge-colors>
+            <item res='@*android:color/profile_badge_1' />
+        </badge-colors>
+    </full-type>
+</user-types>
diff --git a/services/tests/servicestests/res/xml/usertypes_test_illegalOemName.xml b/services/tests/servicestests/res/xml/usertypes_test_illegalOemName.xml
new file mode 100644
index 0000000..f91df1f
--- /dev/null
+++ b/services/tests/servicestests/res/xml/usertypes_test_illegalOemName.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<user-types>
+    <profile-type name='android.aosp.legal' max-allowed-per-parent='12' />
+    <profile-type name='android.oem.illegal.name' max-allowed-per-parent='14' />
+</user-types>
diff --git a/services/tests/servicestests/res/xml/usertypes_test_illegalUserBaseType.xml b/services/tests/servicestests/res/xml/usertypes_test_illegalUserBaseType.xml
new file mode 100644
index 0000000..0785655
--- /dev/null
+++ b/services/tests/servicestests/res/xml/usertypes_test_illegalUserBaseType.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<user-types>
+    <profile-type name='android.test' max-allowed-per-parent='12' />
+</user-types>
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
new file mode 100644
index 0000000..b6c8fbd
--- /dev/null
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<user-types>
+    <profile-type
+        name='android.test.2'
+        max-allowed-per-parent='12'
+        icon-badge='@*android:drawable/ic_corp_icon_badge_case'
+        badge-plain='garbage'
+        badge-no-background='@*android:drawable/ic_corp_badge_no_background'
+        >
+        <badge-labels>
+            <item res='@*android:string/managed_profile_label_badge' />
+            <item res='@*android:string/managed_profile_label_badge_2' />
+        </badge-labels>
+        <badge-colors>
+            <item res='@*android:color/profile_badge_1' />
+            <item res='@*android:color/profile_badge_2' />
+        </badge-colors>
+        <default-restrictions no_remove_user='true' no_bluetooth='true' />
+    </profile-type>
+    <profile-type name='custom.test.1' max-allowed-per-parent='14' />
+</user-types>
diff --git a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
index 9692c25..8b5444c 100644
--- a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
@@ -61,6 +61,7 @@
 import com.android.server.location.GnssNavigationMessageProvider;
 import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
 import com.android.server.location.GnssStatusListenerHelper;
+import com.android.server.location.LocationUsageLogger;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index b5e5deb..67075ed 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -705,6 +705,26 @@
         assertTrue(displayList.equals(mExpectedDisplayList));
     }
 
+    @Test
+    public void setAccessibilityWindowIdToSurfaceMetadata()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        int windowId = -1;
+        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
+            if (mA11yWindowTokens.valueAt(i).equals(token)) {
+                windowId = mA11yWindowTokens.keyAt(i);
+            }
+        }
+        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), windowId);
+
+        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), -1);
+    }
+
     private void startTrackingPerDisplay(int displayId) throws RemoteException {
         ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
         // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3f09f57..f54f885 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3673,6 +3673,45 @@
         verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
     }
 
+    public void testSetAutoTimeZoneModifiesSetting() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        dpm.setAutoTimeZone(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
+
+        dpm.setAutoTimeZone(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
+    }
+
+    public void testSetAutoTimeZoneWithPOOnUser0() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupProfileOwnerOnUser0();
+        dpm.setAutoTimeZone(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
+
+        dpm.setAutoTimeZone(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
+    }
+
+    public void testSetAutoTimeZoneFailWithPONotOnUser0() throws Exception {
+        setupProfileOwner();
+        assertExpectException(SecurityException.class, null,
+                () -> dpm.setAutoTimeZone(admin1, false));
+        verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE,
+                0);
+    }
+
+    public void testSetAutoTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        dpm.setAutoTimeZone(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
+
+        dpm.setAutoTimeZone(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
+    }
+
     public void testSetTime() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index fb9c68a..40ada2a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -30,6 +30,7 @@
 
 import android.apex.ApexInfo;
 import android.apex.ApexSessionInfo;
+import android.apex.ApexSessionParams;
 import android.apex.IApexService;
 import android.content.Context;
 import android.content.pm.PackageInfo;
@@ -183,19 +184,18 @@
     public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
         doAnswer(invocation -> {
             throw new Exception();
-        }).when(mApexService).submitStagedSession(anyInt(), any(), any());
+        }).when(mApexService).submitStagedSession(any(), any());
 
         assertThrows(PackageManagerException.class,
-                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+                () -> mApexManager.submitStagedSession(testParamsWithChildren()));
     }
 
     @Test
     public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
-        doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(),
-                any());
+        doThrow(RemoteException.class).when(mApexService).submitStagedSession(any(), any());
 
         assertThrows(RuntimeException.class,
-                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+                () -> mApexManager.submitStagedSession(testParamsWithChildren()));
     }
 
     @Test
@@ -272,6 +272,13 @@
         return stagedSessionInfo;
     }
 
+    private static ApexSessionParams testParamsWithChildren() {
+        ApexSessionParams params = new ApexSessionParams();
+        params.sessionId = TEST_SESSION_ID;
+        params.childSessionIds = TEST_CHILD_SESSION_ID;
+        return params;
+    }
+
     /**
      * Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy
      * succeeded
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 7aadd87..8e74c90 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -25,24 +25,32 @@
 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
 import static android.content.pm.UserInfo.FLAG_SYSTEM;
 
+import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 import static org.testng.Assert.assertThrows;
 
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.frameworks.servicestests.R;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-
 /**
  * Tests for {@link UserTypeDetails} and {@link UserTypeFactory}.
  *
@@ -52,9 +60,17 @@
 @MediumTest
 public class UserManagerServiceUserTypeTest {
 
+    private Resources mResources;
+
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
+    }
+
     @Test
     public void testUserTypeBuilder_createUserType() {
-        UserTypeDetails type = new UserTypeDetails.Builder()
+        final Bundle restrictions = makeRestrictionsBundle("r1", "r2");
+        final UserTypeDetails type = new UserTypeDetails.Builder()
                 .setName("a.name")
                 .setEnabled(true)
                 .setMaxAllowed(21)
@@ -67,7 +83,7 @@
                 .setBadgeNoBackground(30)
                 .setLabel(31)
                 .setMaxAllowedPerParent(32)
-                .setDefaultRestrictions(new ArrayList<>(Arrays.asList("r1", "r2")))
+                .setDefaultRestrictions(restrictions)
                 .createUserTypeDetails();
 
         assertEquals("a.name", type.getName());
@@ -79,7 +95,8 @@
         assertEquals(30, type.getBadgeNoBackground());
         assertEquals(31, type.getLabel());
         assertEquals(32, type.getMaxAllowedPerParent());
-        assertEquals(new ArrayList<>(Arrays.asList("r1", "r2")), type.getDefaultRestrictions());
+        assertTrue(UserRestrictionsUtils.areEqual(restrictions, type.getDefaultRestrictions()));
+        assertNotSame(restrictions, type.getDefaultRestrictions());
 
 
         assertEquals(23, type.getBadgeLabel(0));
@@ -106,8 +123,8 @@
                 .createUserTypeDetails();
 
         assertTrue(type.isEnabled());
-        assertEquals(UserTypeDetails.UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowed());
-        assertEquals(UserTypeDetails.UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowedPerParent());
+        assertEquals(UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowed());
+        assertEquals(UNLIMITED_NUMBER_OF_USERS, type.getMaxAllowedPerParent());
         assertEquals(FLAG_FULL, type.getDefaultUserInfoFlags());
         assertEquals(Resources.ID_NULL, type.getIconBadge());
         assertEquals(Resources.ID_NULL, type.getBadgePlain());
@@ -185,8 +202,173 @@
                 UserInfo.getDefaultUserType(FLAG_EPHEMERAL));
     }
 
+    /** Tests {@link UserTypeFactory#customizeBuilders} for a reasonable xml file. */
+    @Test
+    public void testUserTypeFactoryCustomize_profile() throws Exception {
+        final String userTypeAosp1 = "android.test.1"; // Profile user that is not customized
+        final String userTypeAosp2 = "android.test.2"; // Profile user that is customized
+        final String userTypeOem1 = "custom.test.1"; // Custom-defined profile
+
+        // Mock some "AOSP defaults".
+        final Bundle restrictions = makeRestrictionsBundle("no_config_vpn", "no_config_tethering");
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(userTypeAosp1, new UserTypeDetails.Builder()
+                .setName(userTypeAosp1)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(31)
+                .setDefaultRestrictions(restrictions));
+        builders.put(userTypeAosp2, new UserTypeDetails.Builder()
+                .setName(userTypeAosp1)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(32)
+                .setIconBadge(401)
+                .setBadgeColors(402, 403, 404)
+                .setDefaultRestrictions(restrictions));
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
+        UserTypeFactory.customizeBuilders(builders, parser);
+
+        // userTypeAosp1 should not be modified.
+        UserTypeDetails aospType = builders.get(userTypeAosp1).createUserTypeDetails();
+        assertEquals(31, aospType.getMaxAllowedPerParent());
+        assertEquals(Resources.ID_NULL, aospType.getIconBadge());
+        assertTrue(UserRestrictionsUtils.areEqual(restrictions, aospType.getDefaultRestrictions()));
+
+        // userTypeAosp2 should be modified.
+        aospType = builders.get(userTypeAosp2).createUserTypeDetails();
+        assertEquals(12, aospType.getMaxAllowedPerParent());
+        assertEquals(com.android.internal.R.drawable.ic_corp_icon_badge_case,
+                aospType.getIconBadge());
+        assertEquals(Resources.ID_NULL, aospType.getBadgePlain()); // No resId for 'garbage'
+        assertEquals(com.android.internal.R.drawable.ic_corp_badge_no_background,
+                aospType.getBadgeNoBackground());
+        assertEquals(com.android.internal.R.string.managed_profile_label_badge,
+                aospType.getBadgeLabel(0));
+        assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
+                aospType.getBadgeLabel(1));
+        assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
+                aospType.getBadgeLabel(2));
+        assertEquals(com.android.internal.R.string.managed_profile_label_badge_2,
+                aospType.getBadgeLabel(3));
+        assertEquals(com.android.internal.R.color.profile_badge_1,
+                aospType.getBadgeColor(0));
+        assertEquals(com.android.internal.R.color.profile_badge_2,
+                aospType.getBadgeColor(1));
+        assertEquals(com.android.internal.R.color.profile_badge_2,
+                aospType.getBadgeColor(2));
+        assertEquals(com.android.internal.R.color.profile_badge_2,
+                aospType.getBadgeColor(3));
+        assertTrue(UserRestrictionsUtils.areEqual(
+                makeRestrictionsBundle("no_remove_user", "no_bluetooth"),
+                aospType.getDefaultRestrictions()));
+
+        // userTypeOem1 should be created.
+        UserTypeDetails.Builder customType = builders.get(userTypeOem1);
+        assertNotNull(customType);
+        assertEquals(14, customType.createUserTypeDetails().getMaxAllowedPerParent());
+    }
+
+    /** Tests {@link UserTypeFactory#customizeBuilders} for customizing a FULL user. */
+    @Test
+    public void testUserTypeFactoryCustomize_full() throws Exception {
+        final String userTypeFull = "android.test.1";
+
+        // Mock "AOSP default".
+        final Bundle restrictions = makeRestrictionsBundle("no_config_vpn", "no_config_tethering");
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(userTypeFull, new UserTypeDetails.Builder()
+                .setName(userTypeFull)
+                .setBaseType(FLAG_FULL)
+                .setDefaultRestrictions(restrictions));
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
+        UserTypeFactory.customizeBuilders(builders, parser);
+
+        UserTypeDetails details = builders.get(userTypeFull).createUserTypeDetails();
+        assertEquals(UNLIMITED_NUMBER_OF_USERS, details.getMaxAllowedPerParent());
+        assertTrue(UserRestrictionsUtils.areEqual(
+                makeRestrictionsBundle("no_remove_user", "no_bluetooth"),
+                details.getDefaultRestrictions()));
+        assertEquals(Resources.ID_NULL, details.getBadgeColor(0));
+    }
+
+    /**
+     * Tests {@link UserTypeFactory#customizeBuilders} when custom user type deletes the
+     * badge-colors and restrictions.
+     */
+    @Test
+    public void testUserTypeFactoryCustomize_eraseArray() throws Exception {
+        final String typeName = "android.test";
+
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(typeName, new UserTypeDetails.Builder()
+                .setName(typeName)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(1)
+                .setBadgeColors(501, 502)
+                .setDefaultRestrictions(makeRestrictionsBundle("r1")));
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_eraseArray);
+        UserTypeFactory.customizeBuilders(builders, parser);
+
+        UserTypeDetails typeDetails =  builders.get(typeName).createUserTypeDetails();
+        assertEquals(2, typeDetails.getMaxAllowedPerParent());
+        assertEquals(Resources.ID_NULL, typeDetails.getBadgeColor(0));
+        assertEquals(Resources.ID_NULL, typeDetails.getBadgeColor(1));
+        assertTrue(typeDetails.getDefaultRestrictions().isEmpty());
+    }
+
+    /** Tests {@link UserTypeFactory#customizeBuilders} when custom user type has illegal name. */
+    @Test
+    public void testUserTypeFactoryCustomize_illegalOemName() throws Exception {
+        final String userTypeAosp = "android.aosp.legal";
+        final String userTypeOem = "android.oem.illegal.name"; // Custom-defined profile
+
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(userTypeAosp, new UserTypeDetails.Builder()
+                .setName(userTypeAosp)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(21));
+
+        final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_illegalOemName);
+
+        // parser is illegal because non-AOSP user types cannot be prefixed with "android.".
+        assertThrows(IllegalArgumentException.class,
+                () -> UserTypeFactory.customizeBuilders(builders, parser));
+    }
+
+    /**
+     * Tests {@link UserTypeFactory#customizeBuilders} when illegally customizing a non-profile as
+     * a profile.
+     */
+    @Test
+    public void testUserTypeFactoryCustomize_illegalUserBaseType() throws Exception {
+        final String userTypeFull = "android.test";
+
+        final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+        builders.put(userTypeFull, new UserTypeDetails.Builder()
+                .setName(userTypeFull)
+                .setBaseType(FLAG_FULL)
+                .setMaxAllowedPerParent(21));
+
+        XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_illegalUserBaseType);
+
+        // parser is illegal because userTypeFull is FULL but the tag is for profile-type.
+        assertThrows(IllegalArgumentException.class,
+                () -> UserTypeFactory.customizeBuilders(builders, parser));
+    }
+
     /** Returns a minimal {@link UserTypeDetails.Builder} that can legitimately be created. */
     private UserTypeDetails.Builder getMinimalBuilder() {
         return new UserTypeDetails.Builder().setName("name").setBaseType(FLAG_FULL);
     }
+
+    /** Creates a Bundle of the given String restrictions, each set to true. */
+    private Bundle makeRestrictionsBundle(String ... restrictions) {
+        final Bundle bundle = new Bundle();
+        for (String restriction : restrictions) {
+            bundle.putBoolean(restriction, true);
+        }
+        return bundle;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index dee79bb..b3f1bcd6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -278,26 +278,12 @@
     @MediumTest
     public void testSetUserAdmin() throws Exception {
         UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
-
-        // Assert user is not admin and has SMS and calls restrictions.
         assertFalse(userInfo.isAdmin());
-        assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
-                userInfo.getUserHandle()));
-        assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
-                userInfo.getUserHandle()));
 
-        // Assign admin privileges.
         mUserManager.setUserAdmin(userInfo.id);
 
-        // Refresh.
         userInfo = mUserManager.getUserInfo(userInfo.id);
-
-        // Verify user became admin and SMS and call restrictions are lifted.
         assertTrue(userInfo.isAdmin());
-        assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
-                userInfo.getUserHandle()));
-        assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
-                userInfo.getUserHandle()));
     }
 
     @MediumTest
@@ -631,6 +617,21 @@
     }
 
     @MediumTest
+    public void testDefaultRestrictionsApplied() throws Exception {
+        final UserInfo userInfo = createUser("Useroid", UserManager.USER_TYPE_FULL_SECONDARY, 0);
+        final UserTypeDetails userTypeDetails =
+                UserTypeFactory.getUserTypes().get(UserManager.USER_TYPE_FULL_SECONDARY);
+        final Bundle expectedRestrictions = userTypeDetails.getDefaultRestrictions();
+        // Note this can fail if DO unset those restrictions.
+        for (String restriction : expectedRestrictions.keySet()) {
+            if (expectedRestrictions.getBoolean(restriction)) {
+                assertTrue(
+                        mUserManager.hasUserRestriction(restriction, UserHandle.of(userInfo.id)));
+            }
+        }
+    }
+
+    @MediumTest
     public void testSetDefaultGuestRestrictions() {
         final Bundle origGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
         Bundle restrictions = new Bundle();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
index cb49fef..2429cfc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
@@ -453,7 +453,7 @@
 
         @Override
         public boolean isDeviceTimeZoneInitialized() {
-            return mTimeZoneId != null;
+            return mTimeZoneId.getLatest() != null;
         }
 
         @Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 7c22350..fab6b7f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -52,11 +52,13 @@
 import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.Adjustment;
 import android.service.notification.StatusBarNotification;
+import android.widget.RemoteViews;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -114,7 +116,9 @@
 
         when(mMockContext.getResources()).thenReturn(getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
-        when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.targetSdkVersion = Build.VERSION_CODES.O;
+        when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
     }
 
     private StatusBarNotification getNotification(String pkg, boolean noisy, boolean defaultSound,
@@ -168,6 +172,28 @@
         return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
     }
 
+    private StatusBarNotification getStyledNotification(boolean customContent, boolean customBig,
+            boolean customHeadsUp, Notification.Style style) {
+        final Builder builder = new Builder(mMockContext)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        if (style != null) {
+            builder.setStyle(style);
+        }
+        if (customContent) {
+            builder.setCustomContentView(mock(RemoteViews.class));
+        }
+        if (customBig) {
+            builder.setCustomBigContentView(mock(RemoteViews.class));
+        }
+        if (customHeadsUp) {
+            builder.setCustomHeadsUpContentView(mock(RemoteViews.class));
+        }
+
+        Notification n = builder.build();
+        return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid);
+    }
+
     //
     // Tests
     //
@@ -999,4 +1025,74 @@
 
         assertEquals(IMPORTANCE_LOW, record.getImportance());
     }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_NoRemoteViews() {
+        StatusBarNotification sbn = getStyledNotification(false, false, false, null);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertFalse("false positive detection", record.hasUndecoratedRemoteView());
+    }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_NoRemoteViewsWithStyle() {
+        StatusBarNotification sbn = getStyledNotification(false, false, false,
+                new Notification.BigPictureStyle());
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertFalse("false positive detection", record.hasUndecoratedRemoteView());
+    }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_UndecoratedContent() {
+        StatusBarNotification sbn = getStyledNotification(true, false, false, null);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertTrue("false negative detection", record.hasUndecoratedRemoteView());
+    }
+
+
+    @Test
+    public void testHasUndecoratedRemoteViews_UndecoratedBig() {
+        StatusBarNotification sbn = getStyledNotification(false, true, false, null);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertTrue("false negative detection", record.hasUndecoratedRemoteView());
+    }
+
+
+    @Test
+    public void testHasUndecoratedRemoteViews_UndecoratedHeadsup() {
+        StatusBarNotification sbn = getStyledNotification(false, false, true, null);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertTrue("false negative detection", record.hasUndecoratedRemoteView());
+    }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_DecoratedRemoteViews() {
+        StatusBarNotification sbn = getStyledNotification(true, true, true,
+                new Notification.DecoratedCustomViewStyle());
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertFalse("false positive detection", record.hasUndecoratedRemoteView());
+    }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_DecoratedMediaRemoteViews() {
+        StatusBarNotification sbn = getStyledNotification(true, true, true,
+                new Notification.DecoratedMediaCustomViewStyle());
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertFalse("false positive detection", record.hasUndecoratedRemoteView());
+    }
+
+    @Test
+    public void testHasUndecoratedRemoteViews_UndecoratedWrongStyle() {
+        StatusBarNotification sbn = getStyledNotification(true, true, true,
+                new Notification.BigPictureStyle());
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertTrue("false negative detection", record.hasUndecoratedRemoteView());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5928641..9c17de9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -47,7 +47,7 @@
 import org.junit.runner.RunWith;
 
 /**
- * Tests for the {@link ActivityDisplay} class.
+ * Tests for the {@link DisplayContent} class.
  *
  * Build/Install/Run:
  *  atest WmTests:ActivityDisplayTests
@@ -55,12 +55,13 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
+// TODO(b/144248496): Merge to DisplayContentTests
 public class ActivityDisplayTests extends ActivityTestsBase {
 
     @Test
     public void testLastFocusedStackIsUpdatedWhenMovingStack() {
         // Create a stack at bottom.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack stack =
                 new StackBuilder(mRootActivityContainer).setOnTop(!ON_TOP).build();
         final ActivityStack prevFocusedStack = display.getFocusedStack();
@@ -103,13 +104,13 @@
     }
 
     /**
-     * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is
+     * Test {@link DisplayContent#mPreferredTopFocusableStack} will be cleared when the stack is
      * removed or moved to back, and the focused stack will be according to z-order.
      */
     @Test
     public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
         // Create a display which only contains 2 stacks.
-        final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display);
         final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display);
 
@@ -128,13 +129,13 @@
     }
 
     /**
-     * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
+     * Verifies {@link DisplayContent#remove} should not resume home stack on the removing display.
      */
     @Test
     public void testNotResumeHomeStackOnRemovingDisplay() {
         // Create a display which supports system decoration and allows reparenting stacks to
         // another display when the display is removed.
-        final ActivityDisplay display = new TestActivityDisplay.Builder(
+        final DisplayContent display = new TestDisplayContent.Builder(
                 mService, 1000, 1500).setSystemDecorations(true).build();
         doReturn(false).when(display).shouldDestroyContentOnRemove();
 
@@ -154,7 +155,7 @@
         verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
     }
 
-    private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
+    private ActivityStack createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
         final ActivityStack fullscreenStack = display.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
         final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
@@ -168,7 +169,7 @@
      */
     @Test
     public void testTopRunningActivity() {
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final KeyguardController keyguard = mSupervisor.getKeyguardController();
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
         final ActivityRecord activity = stack.getTopNonFinishingActivity();
@@ -208,7 +209,7 @@
         assertTopRunningActivity(showWhenLockedActivity, display);
     }
 
-    private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) {
+    private static void assertTopRunningActivity(ActivityRecord top, DisplayContent display) {
         assertEquals(top, display.topRunningActivity());
         assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
     }
@@ -218,7 +219,7 @@
      */
     @Test
     public void testAlwaysOnTopStackLocation() {
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
@@ -283,7 +284,7 @@
     }
 
     private void removeStackTests(Runnable runnable) {
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
         final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 7a449b3..89723d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -635,8 +635,8 @@
         final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
         mStack.moveToFront("test");
         // The stack2 is needed here for moving back to simulate the
-        // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
-        // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
+        // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
+        // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
         // stacks. Then when mActivity is finishing, its stack will be invisible (no running
         // activities in the stack) that is the key condition to verify.
         final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 0219539..530adb5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -112,7 +112,7 @@
     @Test
     public void testHandleNonResizableTaskOnSecondaryDisplay() {
         // Create an unresizable task on secondary display.
-        final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         final ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setDisplay(newDisplay).build();
         final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 47f454e..8a1a10d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -54,7 +54,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.content.ComponentName;
@@ -78,7 +77,7 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class ActivityStackTests extends ActivityTestsBase {
-    private ActivityDisplay mDefaultDisplay;
+    private DisplayContent mDefaultDisplay;
     private ActivityStack mStack;
     private Task mTask;
 
@@ -279,7 +278,7 @@
 
     @Test
     public void testMoveStackToBackIncludingParent() {
-        final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
@@ -815,7 +814,7 @@
 
     @SuppressWarnings("TypeParameterUnusedInFormals")
     private ActivityStack createStackForShouldBeVisibleTest(
-            ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
+            DisplayContent display, int windowingMode, int activityType, boolean onTop) {
         final ActivityStack stack;
         if (activityType == ACTIVITY_TYPE_HOME) {
             // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
@@ -998,7 +997,7 @@
     @Test
     public void testFinishCurrentActivity() {
         // Create 2 activities on a new display.
-        final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
@@ -1065,6 +1064,7 @@
         StackOrderChangedListener listener = new StackOrderChangedListener();
         mDefaultDisplay.registerStackOrderChangedListener(listener);
         try {
+            mStack.mReparenting = true;
             mDefaultDisplay.addStack(mStack, 0);
         } finally {
             mDefaultDisplay.unregisterStackOrderChangedListener(listener);
@@ -1156,10 +1156,10 @@
 
     private void verifyShouldSleepActivities(boolean focusedStack,
             boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
-        final ActivityDisplay display = mock(ActivityDisplay.class);
+        final DisplayContent display = mock(DisplayContent.class);
         final KeyguardController keyguardController = mSupervisor.getKeyguardController();
 
-        doReturn(display).when(mRootActivityContainer).getActivityDisplay(anyInt());
+        doReturn(display).when(mStack).getDisplay();
         doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
         doReturn(displaySleeping).when(display).isSleeping();
         doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay();
@@ -1168,7 +1168,7 @@
     }
 
     private static class StackOrderChangedListener
-            implements ActivityDisplay.OnStackOrderChangedListener {
+            implements DisplayContent.OnStackOrderChangedListener {
         public boolean mChanged = false;
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 018c10a..7e22dfc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -47,9 +47,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
-import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -502,7 +502,7 @@
      */
     @Test
     public void testTaskModeViolation() {
-        final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         display.removeAllTasks();
         assertNoTasks(display);
 
@@ -517,7 +517,7 @@
         assertNoTasks(display);
     }
 
-    private void assertNoTasks(ActivityDisplay display) {
+    private void assertNoTasks(DisplayContent display) {
         for (int i = display.getStackCount() - 1; i >= 0; --i) {
             final ActivityStack stack = display.getStackAt(i);
             assertFalse(stack.hasChild());
@@ -761,8 +761,8 @@
                 false /* mockGetLaunchStack */);
 
         // Create a secondary display at bottom.
-        final TestActivityDisplay secondaryDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500)
+        final TestDisplayContent secondaryDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500)
                         .setPosition(POSITION_BOTTOM).build();
         final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -800,8 +800,8 @@
                 false /* mockGetLaunchStack */);
 
         // Create a secondary display with an activity.
-        final TestActivityDisplay secondaryDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500).build();
+        final TestDisplayContent secondaryDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500).build();
         mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
         final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
                 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
@@ -853,7 +853,7 @@
                 false /* mockGetLaunchStack */);
 
         // Create a secondary display at bottom.
-        final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
+        final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
         secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 07b7cf4..591ed51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -126,7 +126,7 @@
         assertEquals(0, removed.size());
         added.clear();
         // Check adding a display
-        ActivityDisplay newDisp1 = new TestActivityDisplay.Builder(mService, 600, 800).build();
+        DisplayContent newDisp1 = new TestDisplayContent.Builder(mService, 600, 800).build();
         assertEquals(1, added.size());
         assertEquals(0, changed.size());
         assertEquals(0, removed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 0021cc5..b72cc94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -77,9 +77,9 @@
         mRootActivityContainer = mService.mRootActivityContainer;
     }
 
-    /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
-    TestActivityDisplay addNewActivityDisplayAt(int position) {
-        return new TestActivityDisplay.Builder(mService, 1000, 1500).setPosition(position).build();
+    /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */
+    TestDisplayContent addNewDisplayContentAt(int position) {
+        return new TestDisplayContent.Builder(mService, 1000, 1500).setPosition(position).build();
     }
 
     /** Sets the default minimum task size to 1 so that tests can use small task sizes */
@@ -381,7 +381,7 @@
 
     static class StackBuilder {
         private final RootActivityContainer mRootActivityContainer;
-        private ActivityDisplay mDisplay;
+        private DisplayContent mDisplay;
         private int mStackId = -1;
         private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
         private int mActivityType = ACTIVITY_TYPE_STANDARD;
@@ -408,15 +408,8 @@
             return this;
         }
 
-        // TODO(display-merge): Remove
-        StackBuilder setDisplay(ActivityDisplay display) {
-            mDisplay = display;
-            return this;
-        }
-
         StackBuilder setDisplay(DisplayContent display) {
-            // TODO(display-merge): Remove cast
-            mDisplay = (ActivityDisplay) display;
+            mDisplay = display;
             return this;
         }
 
@@ -449,7 +442,7 @@
                     if (mOnTop) {
                         // We move the task to front again in order to regain focus after activity
                         // added to the stack.
-                        // Or {@link ActivityDisplay#mPreferredTopFocusableStack} could be other
+                        // Or {@link DisplayContent#mPreferredTopFocusableStack} could be other
                         // stacks (e.g. home stack).
                         stack.moveToFront("createActivityStack");
                     } else {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 6f1e6df..0c7fad4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -181,7 +181,7 @@
 
     @Test
     public void testLandscapeSeascapeRotationByPolicy() {
-        // This instance has been spied in {@link TestActivityDisplay}.
+        // This instance has been spied in {@link TestDisplayContent}.
         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
 
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 14c09eb..ccbafd4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -768,9 +768,8 @@
 
         activity.setRequestedOrientation(newOrientation);
 
-        // TODO(display-merge): Remove cast
-        verify((ActivityDisplay) dc, never()).updateDisplayOverrideConfigurationLocked(any(),
-                eq(activity), anyBoolean(), same(null));
+        verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity),
+                anyBoolean(), same(null));
         assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
     }
 
@@ -964,7 +963,7 @@
                 invocation -> {
                     continued[0] = true;
                     return true;
-                }).when((ActivityDisplay) dc).updateDisplayOverrideConfigurationLocked();
+                }).when(dc).updateDisplayOverrideConfigurationLocked();
         final boolean[] called = new boolean[1];
         mWm.mDisplayRotationController =
                 new IDisplayWindowRotationController.Stub() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 62ab11c..de73645 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -36,6 +36,7 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -45,6 +46,7 @@
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
 
@@ -55,6 +57,10 @@
 import android.util.Pair;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.InsetsState;
+import android.view.ViewRootImpl;
+import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 
 import androidx.test.filters.FlakyTest;
@@ -97,8 +103,6 @@
         final WindowManager.LayoutParams attrs = mWindow.mAttrs;
         attrs.width = MATCH_PARENT;
         attrs.height = MATCH_PARENT;
-        attrs.flags =
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         attrs.format = PixelFormat.TRANSLUCENT;
     }
 
@@ -134,8 +138,186 @@
     }
 
     @Test
+    public void layoutWindowLw_fitStatusBars() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.statusBars());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_fitNavigationBars() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.navigationBars());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
     public void layoutWindowLw_appDrawsBars() {
-        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_forceAppDrawBars() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_onlyDrawBottomBar() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.privateFlags = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_fitAllSides() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.setFitWindowInsetsSides(Side.all());
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_fitTopOnly() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.setFitWindowInsetsSides(Side.TOP);
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_fitMax() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final InsetsState state =
+                mDisplayContent.getInsetsStateController().getInsetsForDispatch(mWindow);
+        state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+        state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
+        mWindow.mAttrs.setFitIgnoreVisibility(true);
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    @Test
+    public void layoutWindowLw_fitNonMax() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        final InsetsState state =
+                mDisplayContent.getInsetsStateController().getInsetsForDispatch(mWindow);
+        state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+        state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
+        mWindow.mAttrs.setFitIgnoreVisibility(false);
+        addWindow(mWindow);
+
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+    }
+
+    // TODO(b/118118435): remove after migration
+    @Test
+    public void layoutWindowLw_appDrawsBarsLegacy() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -148,9 +330,12 @@
         assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
+    // TODO(b/118118435): remove after migration
     @Test
     public void layoutWindowLw_appWontDrawBars() {
-        mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -163,10 +348,13 @@
         assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
     }
 
+    // TODO(b/118118435): remove after migration
     @Test
     public void layoutWindowLw_appWontDrawBars_forceStatusAndNav() throws Exception {
-        mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
+        mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -179,11 +367,14 @@
         assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
+    // TODO(b/118118435): remove after migration (keyguard dialog is not special with the new logic)
     @Test
     public void layoutWindowLw_keyguardDialog_hideNav() {
         mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
-        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        mWindow.mAttrs.setFitWindowInsetsTypes(0 /* types */);
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
@@ -200,6 +391,8 @@
     public void layoutWindowLw_withDisplayCutout() {
         addDisplayCutout();
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -216,6 +409,8 @@
     public void layoutWindowLw_withDisplayCutout_never() {
         addDisplayCutout();
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
         addWindow(mWindow);
 
@@ -233,7 +428,11 @@
     public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
         addDisplayCutout();
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        mWindow.mAttrs.setFitWindowInsetsTypes(
+                mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -243,14 +442,18 @@
         assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
         assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_fullscreen() {
         addDisplayCutout();
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mDisplayContent.getInsetsStateController().getInsetsForDispatch(mWindow)
+                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -267,7 +470,11 @@
     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
         addDisplayCutout();
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mDisplayContent.getInsetsStateController().getInsetsForDispatch(mWindow)
+                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         addWindow(mWindow);
 
@@ -286,6 +493,9 @@
     public void layoutWindowLw_withDisplayCutout_landscape() {
         addDisplayCutout();
         setRotation(ROTATION_90);
+
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -303,6 +513,9 @@
     public void layoutWindowLw_withDisplayCutout_seascape() {
         addDisplayCutout();
         setRotation(ROTATION_270);
+
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -321,7 +534,11 @@
         addDisplayCutout();
         setRotation(ROTATION_90);
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        mWindow.mAttrs.setFitWindowInsetsTypes(
+                mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
         addWindow(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -339,6 +556,7 @@
         addDisplayCutout();
 
         mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
+        mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars() & ~Type.statusBars());
         mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
         mWindow.mAttrs.width = DISPLAY_WIDTH;
         mWindow.mAttrs.height = DISPLAY_HEIGHT;
@@ -356,7 +574,11 @@
         addDisplayCutout();
         setRotation(ROTATION_90);
 
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        mWindow.mAttrs.setFitWindowInsetsTypes(
+                mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         addWindow(mWindow);
 
@@ -372,6 +594,8 @@
 
     @Test
     public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
         addWindow(mWindow);
 
@@ -392,6 +616,8 @@
 
     @Test
     public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
         addWindow(mWindow);
 
@@ -408,9 +634,12 @@
         assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
+    // TODO(b/118118435): remove after removing PolicyControl
     @FlakyTest(bugId = 129711077)
     @Test
     public void layoutWindowLw_withImmersive_SoftInputAdjustResize() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         synchronized (mWm.mGlobalLock) {
             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
             mWindow.mAttrs.flags = 0;
@@ -433,9 +662,12 @@
         }
     }
 
+    // TODO(b/118118435): remove after removing PolicyControl
     @FlakyTest(bugId = 129711077)
     @Test
     public void layoutWindowLw_withImmersive_SoftInputAdjustNothing() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         synchronized (mWm.mGlobalLock) {
             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
             mWindow.mAttrs.flags = 0;
@@ -457,9 +689,12 @@
         }
     }
 
+    // TODO(b/118118435): remove after removing PolicyControl
     @FlakyTest(bugId = 129711077)
     @Test
     public void layoutWindowLw_withForceImmersive_fullscreen() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         synchronized (mWm.mGlobalLock) {
             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
             mWindow.mAttrs.flags = 0;
@@ -481,9 +716,12 @@
         }
     }
 
+    // TODO(b/118118435): remove after removing PolicyControl
     @FlakyTest(bugId = 129711077)
     @Test
     public void layoutWindowLw_withForceImmersive_nonFullscreen() {
+        assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
+
         synchronized (mWm.mGlobalLock) {
             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
             mWindow.mAttrs.flags = 0;
@@ -509,6 +747,9 @@
 
     @Test
     public void layoutHint_appWindow() {
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
         // Initialize DisplayFrames
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
@@ -530,6 +771,9 @@
 
     @Test
     public void layoutHint_appWindowInTask() {
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
         // Initialize DisplayFrames
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
@@ -553,6 +797,9 @@
 
     @Test
     public void layoutHint_appWindowInTask_outsideContentFrame() {
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
         // Initialize DisplayFrames
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
@@ -581,7 +828,8 @@
     public void forceShowSystemBars_clearsSystemUIFlags() {
         mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
         mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.flags =
+                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
         mDisplayPolicy.setForceShowSystemBars(true);
         addWindow(mWindow);
@@ -600,7 +848,8 @@
     @Test
     public void testScreenDecorWindows() {
         final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow");
-        decorWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+        mWindow.mAttrs.flags = FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR
+                | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         decorWindow.mAttrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
         addWindow(decorWindow);
         addWindow(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index d4558dc..d0b3350 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -78,6 +78,8 @@
         resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
         resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
         resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
+        resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT);
+        resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT);
         doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources();
         doReturn(true).when(mDisplayPolicy).hasNavigationBar();
         doReturn(true).when(mDisplayPolicy).hasStatusBar();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 9e5d9da..84914bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -80,7 +80,7 @@
 
     private TestPersisterQueue mPersisterQueue;
     private File mFolder;
-    private ActivityDisplay mTestDisplay;
+    private DisplayContent mTestDisplay;
     private String mDisplayUniqueId;
     private Task mTestTask;
     private Task mTaskWithDifferentUser;
@@ -104,9 +104,9 @@
         deleteRecursively(mFolder);
 
         mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
-        mTestDisplay = new TestActivityDisplay.Builder(mService, 1000, 1500)
+        mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
                 .setUniqueId(mDisplayUniqueId).build();
-        when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId)))
+        when(mRootActivityContainer.getDisplayContent(eq(mDisplayUniqueId)))
                 .thenReturn(mTestDisplay);
 
         ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
@@ -180,7 +180,7 @@
     public void testReturnsEmptyDisplayIfDisplayIsNotFound() {
         mTarget.saveTask(mTestTask);
 
-        when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId))).thenReturn(null);
+        when(mRootActivityContainer.getDisplayContent(eq(mDisplayUniqueId))).thenReturn(null);
 
         mTarget.getLaunchParams(mTestTask, null, mResult);
 
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 09d7b54..eaf4aa3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -102,7 +102,7 @@
             UserManager.USER_TYPE_PROFILE_MANAGED);
     private static final int INVALID_STACK_ID = 999;
 
-    private ActivityDisplay mDisplay;
+    private DisplayContent mDisplay;
     private ActivityStack mStack;
     private TestTaskPersister mTaskPersister;
     private TestRecentTasks mRecentTasks;
@@ -117,7 +117,7 @@
     public void setUp() throws Exception {
         mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
         spyOn(mTaskPersister);
-        mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+        mDisplay = mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY);
 
         // Set the recent tasks we should use for testing in this class.
         mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
@@ -653,8 +653,8 @@
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
 
-        final ActivityDisplay singleTaskDisplay =
-                addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent singleTaskDisplay =
+                addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         singleTaskDisplay.setDisplayToSingleTaskInstance();
         ActivityStack singleTaskStack = singleTaskDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -833,7 +833,7 @@
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
         final ActivityStack homeStack = mDisplay.getHomeStack();
-        final ActivityDisplay otherDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         final ActivityStack otherDisplayStack = otherDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 2374847..945928d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -138,8 +138,7 @@
     @Test
     public void testIncludedApps_expectTargetAndVisible() {
         mWm.setRecentsAnimationController(mController);
-        // TODO(display-merge): Remove cast
-        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+        final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -164,8 +163,7 @@
     @Test
     public void testWallpaperIncluded_expectTarget() throws Exception {
         mWm.setRecentsAnimationController(mController);
-        // TODO(display-merge): Remove cast
-        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+        final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeAppWindow =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -194,8 +192,7 @@
     @Test
     public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
         mWm.setRecentsAnimationController(mController);
-        // TODO(display-merge): Remove cast
-        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+        final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -226,8 +223,7 @@
     @Test
     public void testFinish_expectTargetAndWallpaperAdaptersRemoved() {
         mWm.setRecentsAnimationController(mController);
-        // TODO(display-merge): Remove cast
-        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
+        final ActivityStack homeStack = mDisplayContent.getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 8fbb16c..07be3e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -88,7 +88,7 @@
 
     @Test
     public void testRecentsActivityVisiblility() {
-        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         ActivityStack recentsStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
         ActivityRecord recentActivity = new ActivityBuilder(mService)
@@ -116,7 +116,7 @@
 
     @Test
     public void testPreloadRecentsActivity() {
-        final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent defaultDisplay = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack homeStack =
                 defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
         defaultDisplay.positionStackAtTop(homeStack, false /* includingParents */);
@@ -149,7 +149,7 @@
         mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
                 null /* recentsAnimationRunner */);
 
-        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         ActivityStack recentsStack = display.getStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS);
         assertThat(recentsStack).isNotNull();
@@ -178,7 +178,7 @@
     @Test
     public void testRestartRecentsActivity() throws Exception {
         // Have a recents activity that is not attached to its process (ActivityRecord.app = null).
-        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         ActivityStack recentsStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
         ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
@@ -207,7 +207,7 @@
 
     @Test
     public void testSetLaunchTaskBehindOfTargetActivity() {
-        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
         ActivityStack homeStack = display.getHomeStack();
         // Assume the home activity support recents.
@@ -253,7 +253,7 @@
 
     @Test
     public void testCancelAnimationOnVisibleStackOrderChange() {
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
         ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -299,7 +299,7 @@
 
     @Test
     public void testKeepAnimationOnHiddenStackOrderChange() {
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         new ActivityBuilder(mService)
@@ -335,7 +335,7 @@
 
     @Test
     public void testMultipleUserHomeActivity_findUserHomeTask() {
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack homeStack = display.getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
         ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService)
                 .setStack(homeStack)
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 5417ade..2d45a59 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -128,7 +128,7 @@
         mRootActivityContainer.moveActivityToPinnedStack(firstActivity, sourceBounds,
                 0f /*aspectRatio*/, "initialMove");
 
-        final ActivityDisplay display = mFullscreenStack.getDisplay();
+        final DisplayContent display = mFullscreenStack.getDisplay();
         ActivityStack pinnedStack = display.getPinnedStack();
         // Ensure a task has moved over.
         ensureStackPlacement(pinnedStack, firstActivity);
@@ -166,7 +166,7 @@
 
     @Test
     public void testApplySleepTokens() {
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final KeyguardController keyguard = mSupervisor.getKeyguardController();
         final ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setCreateActivity(false)
@@ -202,7 +202,7 @@
                 false /* expectResumeTopActivity */);
     }
 
-    private void verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard,
+    private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
             ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep,
             boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
             boolean expectResumeTopActivity) {
@@ -225,7 +225,7 @@
      */
     @Test
     public void testRemovingStackOnAppCrash() {
-        final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent defaultDisplay = mRootActivityContainer.getDefaultDisplay();
         final int originalStackCount = defaultDisplay.getStackCount();
         final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
@@ -336,7 +336,7 @@
     @Test
     public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
         // Create stack/task on default display.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
                 .setOnTop(false)
                 .build();
@@ -360,14 +360,14 @@
     @Test
     public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
         // Create stack/task on default display.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */);
         final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
 
         // Create Recents on secondary display.
-        final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
-                ActivityDisplay.POSITION_TOP);
+        final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+                DisplayContent.POSITION_TOP);
         final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -387,7 +387,7 @@
     @Test
     public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
         // Create a stack at bottom.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -415,8 +415,9 @@
     @Test
     public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
         mFullscreenStack.removeIfPossible();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
+        mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
+                .removeIfPossible();
+        mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY)
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
 
         doReturn(true).when(mRootActivityContainer).resumeHomeActivity(any(), any(), anyInt());
@@ -437,13 +438,14 @@
     @Test
     public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
         mFullscreenStack.removeIfPossible();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
+        mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
+                .removeIfPossible();
+        mService.mRootActivityContainer.getDisplayContent(DEFAULT_DISPLAY)
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
 
         // Create an activity on secondary display.
-        final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
-                ActivityDisplay.POSITION_TOP);
+        final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+                DisplayContent.POSITION_TOP);
         final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -467,7 +469,7 @@
     @Test
     public void testResumeActivityLingeringTransition() {
         // Create a stack at top.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -487,7 +489,7 @@
     @Test
     public void testResumeActivityLingeringTransition_notExecuted() {
         // Create a stack at bottom.
-        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -515,8 +517,8 @@
         mockResolveSecondaryHomeActivity();
 
         // Create secondary displays.
-        final TestActivityDisplay secondDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500)
+        final TestDisplayContent secondDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500)
                         .setSystemDecorations(true).build();
 
         doReturn(true).when(mRootActivityContainer)
@@ -582,8 +584,8 @@
     @Test
     public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
         // Create secondary displays.
-        final TestActivityDisplay secondDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500)
+        final TestDisplayContent secondDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500)
                         .setSystemDecorations(true).build();
 
         // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
@@ -608,8 +610,8 @@
     @Test
     public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
         // Create secondary displays.
-        final TestActivityDisplay secondDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500)
+        final TestDisplayContent secondDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500)
                         .setSystemDecorations(false).build();
 
         mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
@@ -831,8 +833,8 @@
     @Test
     public void testGetLaunchStackWithRealCallerId() {
         // Create a non-system owned virtual display.
-        final TestActivityDisplay secondaryDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 1500)
+        final TestDisplayContent secondaryDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 1500)
                         .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
 
         // Create an activity with specify the original launch pid / uid.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 66f4d2a..b32cb8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -57,9 +57,9 @@
     @Test
     public void testCollectTasksByLastActiveTime() {
         // Create a number of stacks with tasks (of incrementing active time)
-        final ArrayList<ActivityDisplay> displays = new ArrayList<>();
-        final ActivityDisplay display =
-                new TestActivityDisplay.Builder(mService, 1000, 2500).build();
+        final ArrayList<DisplayContent> displays = new ArrayList<>();
+        final DisplayContent display =
+                new TestDisplayContent.Builder(mService, 1000, 2500).build();
         displays.add(display);
 
         final int numStacks = 2;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 46f95ed..be0fd2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -67,7 +67,7 @@
     private Task mTask;
     private ActivityRecord mActivity;
 
-    private void setUpApp(ActivityDisplay display) {
+    private void setUpApp(DisplayContent display) {
         mStack = new StackBuilder(mRootActivityContainer).setDisplay(display).build();
         mTask = mStack.getBottomMostTask();
         mActivity = mTask.getTopNonFinishingActivity();
@@ -79,7 +79,7 @@
 
     @Test
     public void testRestartProcessIfVisible() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
         doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
         mActivity.mVisibleRequested = true;
         mActivity.setSavedState(null /* savedState */);
@@ -99,7 +99,7 @@
     public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
         removeGlobalMinSizeRestriction();
         // create freeform display and a freeform app
-        ActivityDisplay display = new TestActivityDisplay.Builder(mService, 2000, 1000)
+        DisplayContent display = new TestDisplayContent.Builder(mService, 2000, 1000)
                 .setCanRotate(false)
                 .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
         setUpApp(display);
@@ -126,7 +126,7 @@
     @Test
     public void testFixedAspectRatioBoundsWithDecor() {
         final int decorHeight = 200; // e.g. The device has cutout.
-        setUpApp(new TestActivityDisplay.Builder(mService, 600, 800)
+        setUpApp(new TestDisplayContent.Builder(mService, 600, 800)
                 .setNotch(decorHeight).build());
 
         mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
@@ -152,11 +152,11 @@
 
     @Test
     public void testFixedScreenConfigurationWhenMovingToDisplay() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
 
         // Make a new less-tall display with lower density
-        final ActivityDisplay newDisplay =
-                new TestActivityDisplay.Builder(mService, 1000, 2000)
+        final DisplayContent newDisplay =
+                new TestDisplayContent.Builder(mService, 1000, 2000)
                         .setDensityDpi(200).build();
 
         mActivity = new ActivityBuilder(mService)
@@ -180,7 +180,7 @@
 
     @Test
     public void testFixedScreenBoundsWhenDisplaySizeChanged() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
         prepareUnresizable(-1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFalse(mActivity.inSizeCompatMode());
 
@@ -203,7 +203,7 @@
 
     @Test
     public void testLetterboxFullscreenBounds() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
 
         // Fill out required fields on default display since WM-side is mocked out
         prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
@@ -213,10 +213,10 @@
 
     @Test
     public void testMoveToDifferentOrientDisplay() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
 
-        final ActivityDisplay newDisplay =
-                new TestActivityDisplay.Builder(mService, 2000, 1000)
+        final DisplayContent newDisplay =
+                new TestDisplayContent.Builder(mService, 2000, 1000)
                         .setCanRotate(false).build();
 
         prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -235,7 +235,7 @@
     @Test
     public void testFixedOrientRotateCutoutDisplay() {
         // Create a display with a notch/cutout
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).setNotch(60).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).setNotch(60).build());
         prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
 
         final Rect origBounds = new Rect(mActivity.getBounds());
@@ -259,7 +259,7 @@
 
     @Test
     public void testFixedAspOrientChangeOrient() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
 
         prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
         // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted.
@@ -286,7 +286,7 @@
 
     @Test
     public void testFixedScreenLayoutSizeBits() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
         final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
                 | Configuration.SCREENLAYOUT_SIZE_NORMAL
                 | Configuration.SCREENLAYOUT_COMPAT_NEEDED;
@@ -314,9 +314,9 @@
 
     @Test
     public void testResetNonVisibleActivity() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
         prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
-        final ActivityDisplay display = mStack.getDisplay();
+        final DisplayContent display = mStack.getDisplay();
         // Resize the display so the activity is in size compatibility mode.
         resizeDisplay(display, 900, 1800);
 
@@ -354,7 +354,7 @@
      */
     @Test
     public void testHandleActivitySizeCompatMode() {
-        setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2000).build());
+        setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000).build());
         ActivityRecord activity = mActivity;
         activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
         prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -412,7 +412,7 @@
         ensureActivityConfiguration();
     }
 
-    private void resizeDisplay(ActivityDisplay display, int width, int height) {
+    private void resizeDisplay(DisplayContent display, int width, int height) {
         final DisplayContent displayContent = display.mDisplayContent;
         displayContent.mBaseDisplayWidth = width;
         displayContent.mBaseDisplayHeight = height;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a172b65..811f46f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -286,13 +286,12 @@
 
         // Mock root, some default display, and home stack.
         spyOn(mWmService.mRoot);
-        final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay();
+        final DisplayContent display = mAtmService.mRootActivityContainer.getDefaultDisplay();
         // Set default display to be in fullscreen mode. Devices with PC feature may start their
         // default display in freeform mode but some of tests in WmTests have implicit assumption on
         // that the default display is in fullscreen mode.
         display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
         spyOn(display);
-        spyOn(display.mDisplayContent);
         final ActivityStack homeStack = display.getStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
         spyOn(homeStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 9a91efe..5aa41eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -107,7 +107,7 @@
     // =============================
     @Test
     public void testDefaultToPrimaryDisplay() {
-        createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+        createNewDisplayContent(WINDOWING_MODE_FREEFORM);
 
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                 mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
@@ -127,8 +127,8 @@
 
     @Test
     public void testUsesPreviousDisplayIdIfSet() {
-        createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
-        final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+        createNewDisplayContent(WINDOWING_MODE_FREEFORM);
+        final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
 
         mCurrent.mPreferredDisplayId = display.mDisplayId;
 
@@ -140,9 +140,9 @@
 
     @Test
     public void testUsesSourcesDisplayIdIfSet() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -157,9 +157,9 @@
 
     @Test
     public void testUsesOptionsDisplayIdIfSet() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -176,9 +176,9 @@
 
     @Test
     public void testUsesTasksDisplayIdPriorToSourceIfSet() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -193,7 +193,7 @@
 
     @Test
     public void testUsesTaskDisplayIdIfSet() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
         ActivityRecord source = createSourceActivity(freeformDisplay);
 
@@ -205,9 +205,9 @@
 
     @Test
     public void testUsesNoDisplaySourceHandoverDisplayIdIfSet() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
 
         mCurrent.mPreferredDisplayId = fullscreenDisplay.mDisplayId;
@@ -227,7 +227,7 @@
     // =====================================
     @Test
     public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -258,7 +258,7 @@
 
     @Test
     public void testInheritsFreeformModeFromSourceOnFullscreenDisplay() {
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
         source.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -272,7 +272,7 @@
 
     @Test
     public void testKeepsPictureInPictureLaunchModeInOptions() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -289,7 +289,7 @@
 
     @Test
     public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -321,7 +321,7 @@
 
     @Test
     public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -338,7 +338,7 @@
 
     @Test
     public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -382,7 +382,7 @@
 
     @Test
     public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -397,7 +397,7 @@
 
     @Test
     public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -414,7 +414,7 @@
     @Test
     public void testForceMaximizesUnresizeableApp() {
         mService.mSizeCompatFreeform = false;
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -437,7 +437,7 @@
     @Test
     public void testLaunchesAppInWindowOnFreeformDisplay() {
         mService.mSizeCompatFreeform = true;
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
@@ -494,7 +494,7 @@
 
     @Test
     public void testUsesFullscreenWhenRequestedOnFreeformDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -510,7 +510,7 @@
 
     @Test
     public void testUsesFreeformByDefaultForPostNApp() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -525,7 +525,7 @@
 
     @Test
     public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -559,7 +559,7 @@
     // ===============================
     @Test
     public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -578,7 +578,7 @@
 
     @Test
     public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() {
-        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FULLSCREEN);
         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
         source.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -595,7 +595,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -611,7 +611,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -627,7 +627,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -644,7 +644,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -660,7 +660,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -676,7 +676,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -693,7 +693,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -709,7 +709,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -725,7 +725,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -741,7 +741,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -757,7 +757,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -773,7 +773,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -789,7 +789,7 @@
 
     @Test
     public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -805,7 +805,7 @@
 
     @Test
     public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -821,7 +821,7 @@
 
     @Test
     public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -836,7 +836,7 @@
 
     @Test
     public void testReturnBoundsForFullscreenWindowingMode() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
@@ -851,7 +851,7 @@
 
     @Test
     public void testUsesDisplayOrientationForNoSensorOrientation() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -875,7 +875,7 @@
 
     @Test
     public void testRespectsAppRequestedOrientation_Landscape() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -892,7 +892,7 @@
 
     @Test
     public void testRespectsAppRequestedOrientation_Portrait() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -909,7 +909,7 @@
 
     @Test
     public void testDefaultSizeSmallerThanBigScreen() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -933,7 +933,7 @@
 
     @Test
     public void testDefaultFreeformSizeCenteredToDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -954,7 +954,7 @@
 
     @Test
     public void testCascadesToSourceSizeForFreeform() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -981,7 +981,7 @@
 
     @Test
     public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1003,7 +1003,7 @@
 
     @Test
     public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1025,7 +1025,7 @@
 
     @Test
     public void testAdjustBoundsToFitNewDisplay_LargerThanDisplay() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1052,7 +1052,7 @@
         overrideConfig.setLayoutDirection(new Locale("ar", "EG"));
         mRootActivityContainer.onRequestedOverrideConfigurationChanged(overrideConfig);
 
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1073,7 +1073,7 @@
 
     @Test
     public void testRespectsLayoutMinDimensions() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         // This test case requires a relatively big app bounds to ensure the default size calculated
@@ -1098,7 +1098,7 @@
 
     @Test
     public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1115,7 +1115,7 @@
 
     @Test
     public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
@@ -1132,7 +1132,7 @@
 
     @Test
     public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
@@ -1149,7 +1149,7 @@
 
     @Test
     public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
@@ -1166,7 +1166,7 @@
 
     @Test
     public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
@@ -1183,7 +1183,7 @@
 
     @Test
     public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
@@ -1200,7 +1200,7 @@
 
     @Test
     public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
@@ -1230,7 +1230,7 @@
 
     @Test
     public void testAdjustsBoundsToFitInDisplayFullyResolvedBounds() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         mCurrent.mPreferredDisplayId = Display.INVALID_DISPLAY;
@@ -1248,7 +1248,7 @@
 
     @Test
     public void testAdjustsBoundsToAvoidConflictFullyResolvedBounds() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
         addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 200, 100));
@@ -1283,7 +1283,7 @@
     @Test
     public void testNoMultiDisplaySupports() {
         final boolean orgValue = mService.mSupportsMultiDisplay;
-        final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+        final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
         mCurrent.mPreferredDisplayId = display.mDisplayId;
 
         try {
@@ -1296,8 +1296,8 @@
         }
     }
 
-    private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
-        final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+    private TestDisplayContent createNewDisplayContent(int windowingMode) {
+        final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
         display.setWindowingMode(windowingMode);
         display.setBounds(DISPLAY_BOUNDS);
         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
@@ -1311,13 +1311,13 @@
         return display;
     }
 
-    private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+    private ActivityRecord createSourceActivity(TestDisplayContent display) {
         final ActivityStack stack = display.createStack(display.getWindowingMode(),
                 ACTIVITY_TYPE_STANDARD, true);
         return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
     }
 
-    private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+    private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
         final ActivityStack stack = display.createStack(display.getWindowingMode(),
                 ACTIVITY_TYPE_STANDARD, true);
         stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 39e7885..1a18df5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -193,7 +193,7 @@
     @FlakyTest(bugId = 137879065)
     public void testFitWithinBounds() {
         final Rect parentBounds = new Rect(10, 10, 200, 200);
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
@@ -232,7 +232,7 @@
     @Test
     @FlakyTest(bugId = 137879065)
     public void testBoundsOnModeChangeFreeformToFullscreen() {
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
         Task task = stack.getBottomMostTask();
@@ -265,9 +265,9 @@
     public void testFullscreenBoundsForcedOrientation() {
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
         final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
-        ActivityDisplay display = new TestActivityDisplay.Builder(
+        DisplayContent display = new TestDisplayContent.Builder(
                 mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
-        assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+        assertTrue(mRootActivityContainer.getDisplayContent(display.mDisplayId) != null);
         // Fix the display orientation to landscape which is the natural rotation (0) for the test
         // display.
         final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
@@ -328,7 +328,7 @@
     @Test
     public void testIgnoresForcedOrientationWhenParentHandles() {
         final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
-        ActivityDisplay display = new TestActivityDisplay.Builder(
+        DisplayContent display = new TestDisplayContent.Builder(
                 mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
 
         display.getRequestedOverrideConfiguration().orientation =
@@ -809,7 +809,7 @@
     private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
             Rect expectedConfigBounds) {
 
-        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        DisplayContent display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
         Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 817344f..2d418ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -74,7 +74,7 @@
                 0 /* systemUiVisibility */, false /* isTranslucent */);
         mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
                 createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
-                taskBounds, ORIENTATION_PORTRAIT);
+                taskBounds, ORIENTATION_PORTRAIT, null /* insetsState */);
     }
 
     private static TaskDescription createTaskDescription(int background, int statusBar,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
similarity index 94%
rename from services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
rename to services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 247cd87..325cea7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -35,11 +35,11 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 
-class TestActivityDisplay extends ActivityDisplay {
+class TestDisplayContent extends DisplayContent {
     private final ActivityStackSupervisor mSupervisor;
 
-    private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
-        super(supervisor.mService.mRootActivityContainer, display);
+    private TestDisplayContent(ActivityStackSupervisor supervisor, Display display) {
+        super(display, supervisor.mService.mRootActivityContainer);
         // Normally this comes from display-properties as exposed by WM. Without that, just
         // hard-code to FULLSCREEN for tests.
         setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -140,13 +140,13 @@
             mInfo.logicalDensityDpi = dpi;
             return this;
         }
-        TestActivityDisplay build() {
+        TestDisplayContent build() {
             final int displayId = SystemServicesTestRule.sNextDisplayId++;
             final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                     mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-            final TestActivityDisplay newDisplay;
+            final TestDisplayContent newDisplay;
             synchronized (mService.mGlobalLock) {
-                newDisplay = new TestActivityDisplay(mService.mStackSupervisor, display);
+                newDisplay = new TestDisplayContent(mService.mStackSupervisor, display);
                 mService.mRootActivityContainer.addChild(newDisplay, mPosition);
             }
             // disable the normal system decorations
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 4d25a83..6108db3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -61,33 +61,33 @@
         assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Register to display 1 as a listener.
-        TestActivityDisplay testActivityDisplay1 = createTestActivityDisplayInContainer();
-        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertTrue(testActivityDisplay1.containsListener(mWpc));
-        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
+        TestDisplayContent testDisplayContent1 = createTestDisplayContentInContainer();
+        mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent1);
+        assertTrue(testDisplayContent1.containsListener(mWpc));
+        assertEquals(testDisplayContent1.mDisplayId, mWpc.getDisplayId());
 
         // Move to display 2.
-        TestActivityDisplay testActivityDisplay2 = createTestActivityDisplayInContainer();
-        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay2);
-        assertFalse(testActivityDisplay1.containsListener(mWpc));
-        assertTrue(testActivityDisplay2.containsListener(mWpc));
-        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
+        TestDisplayContent testDisplayContent2 = createTestDisplayContentInContainer();
+        mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent2);
+        assertFalse(testDisplayContent1.containsListener(mWpc));
+        assertTrue(testDisplayContent2.containsListener(mWpc));
+        assertEquals(testDisplayContent2.mDisplayId, mWpc.getDisplayId());
 
-        // Null ActivityDisplay will not change anything.
+        // Null DisplayContent will not change anything.
         mWpc.registerDisplayConfigurationListenerLocked(null);
-        assertTrue(testActivityDisplay2.containsListener(mWpc));
-        assertEquals(testActivityDisplay2.mDisplayId, mWpc.getDisplayId());
+        assertTrue(testDisplayContent2.containsListener(mWpc));
+        assertEquals(testDisplayContent2.mDisplayId, mWpc.getDisplayId());
 
         // Unregister listener will remove the wpc from registered displays.
         mWpc.unregisterDisplayConfigurationListenerLocked();
-        assertFalse(testActivityDisplay1.containsListener(mWpc));
-        assertFalse(testActivityDisplay2.containsListener(mWpc));
+        assertFalse(testDisplayContent1.containsListener(mWpc));
+        assertFalse(testDisplayContent2.containsListener(mWpc));
         assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
 
         // Unregistration still work even if the display was removed.
-        mWpc.registerDisplayConfigurationListenerLocked(testActivityDisplay1);
-        assertEquals(testActivityDisplay1.mDisplayId, mWpc.getDisplayId());
-        mRootActivityContainer.removeChild(testActivityDisplay1);
+        mWpc.registerDisplayConfigurationListenerLocked(testDisplayContent1);
+        assertEquals(testDisplayContent1.mDisplayId, mWpc.getDisplayId());
+        mRootActivityContainer.removeChild(testDisplayContent1);
         mWpc.unregisterDisplayConfigurationListenerLocked();
         assertEquals(INVALID_DISPLAY, mWpc.getDisplayId());
     }
@@ -129,7 +129,7 @@
         orderVerifier.verifyNoMoreInteractions();
     }
 
-    private TestActivityDisplay createTestActivityDisplayInContainer() {
-        return new TestActivityDisplay.Builder(mService, 1000, 1500).build();
+    private TestDisplayContent createTestDisplayContentInContainer() {
+        return new TestDisplayContent.Builder(mService, 1000, 1500).build();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 22ba90b..6f53428 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -340,8 +340,8 @@
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
     DisplayContent createNewDisplay(DisplayInfo info) {
-        final ActivityDisplay display =
-                new TestActivityDisplay.Builder(mWm.mAtmService, info).build();
+        final DisplayContent display =
+                new TestDisplayContent.Builder(mWm.mAtmService, info).build();
         return display.mDisplayContent;
     }
 
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 4d01e33..fbb1380 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -604,9 +604,14 @@
     }
 
     private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
-        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
                 Context.TELEPHONY_SERVICE);
-        return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
+            return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b71bd85..94085e9 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -210,6 +210,12 @@
     private int mSubscriptionType;
 
     /**
+     * Whether uicc applications are configured to enable or disable.
+     * By default it's true.
+     */
+    private boolean mAreUiccApplicationsEnabled = true;
+
+    /**
      * @hide
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
@@ -220,7 +226,7 @@
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
                 false, null, false, TelephonyManager.UNKNOWN_CARRIER_ID,
                 SubscriptionManager.PROFILE_CLASS_DEFAULT,
-                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
     }
 
     /**
@@ -234,7 +240,7 @@
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1,
                 isOpportunistic, groupUUID, false, carrierId, profileClass,
-                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
     }
 
     /**
@@ -246,7 +252,8 @@
             @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId,
             boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled,
             int carrierId, int profileClass, int subType, @Nullable String groupOwner,
-            @Nullable UiccAccessRule[] carrierConfigAccessRules) {
+            @Nullable UiccAccessRule[] carrierConfigAccessRules,
+            boolean areUiccApplicationsEnabled) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -272,6 +279,7 @@
         this.mSubscriptionType = subType;
         this.mGroupOwner = groupOwner;
         this.mCarrierConfigAccessRules = carrierConfigAccessRules;
+        this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled;
     }
 
     /**
@@ -660,6 +668,15 @@
         return mIsGroupDisabled;
     }
 
+    /**
+     * Return whether uicc applications are set to be enabled or disabled.
+     * @hide
+     */
+    @SystemApi
+    public boolean areUiccApplicationsEnabled() {
+        return mAreUiccApplicationsEnabled;
+    }
+
     public static final @android.annotation.NonNull Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
         @Override
         public SubscriptionInfo createFromParcel(Parcel source) {
@@ -691,12 +708,13 @@
             String groupOwner = source.readString();
             UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
                 UiccAccessRule.CREATOR);
+            boolean areUiccApplicationsEnabled = source.readBoolean();
 
             SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
                     carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
                     countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
                     groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
-                    carrierConfigAccessRules);
+                    carrierConfigAccessRules, areUiccApplicationsEnabled);
             info.setAssociatedPlmns(ehplmns, hplmns);
             return info;
         }
@@ -736,6 +754,7 @@
         dest.writeStringArray(mHplmns);
         dest.writeString(mGroupOwner);
         dest.writeTypedArray(mCarrierConfigAccessRules, flags);
+        dest.writeBoolean(mAreUiccApplicationsEnabled);
     }
 
     @Override
@@ -778,15 +797,16 @@
                 + " hplmns=" + Arrays.toString(mHplmns)
                 + " subscriptionType=" + mSubscriptionType
                 + " mGroupOwner=" + mGroupOwner
-                + " carrierConfigAccessRules=" + mCarrierConfigAccessRules + "}";
+                + " carrierConfigAccessRules=" + mCarrierConfigAccessRules
+                + " mAreUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}";
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
-                mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
-                mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mNativeAccessRules,
-                mIsGroupDisabled, mCarrierId, mProfileClass, mGroupOwner);
+                mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString,
+                mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled,
+                mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled);
     }
 
     @Override
@@ -809,6 +829,7 @@
                 && mIsEmbedded == toCompare.mIsEmbedded
                 && mIsOpportunistic == toCompare.mIsOpportunistic
                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
+                && mAreUiccApplicationsEnabled == toCompare.mAreUiccApplicationsEnabled
                 && mCarrierId == toCompare.mCarrierId
                 && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
                 && Objects.equals(mIccId, toCompare.mIccId)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a82ae88..740622d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -835,6 +835,12 @@
     public static final String IMSI = "imsi";
 
     /**
+     * Whether uicc applications is set to be enabled or disabled. By default it's enabled.
+     * @hide
+     */
+    public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+
+    /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
      *
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
index b75d533..407ad19 100644
--- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -16,12 +16,16 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
+import android.os.TelephonyServiceManager;
 import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
 
+import com.android.internal.util.Preconditions;
+
 
 /**
  * Class for performing registration for all telephony services.
@@ -34,6 +38,23 @@
     private TelephonyFrameworkInitializer() {
     }
 
+    private static volatile TelephonyServiceManager sTelephonyServiceManager;
+
+    /**
+     * Sets an instance of {@link TelephonyServiceManager} that allows
+     * the telephony mainline module to register/obtain telephony binder services. This is called
+     * by the platform during the system initialization.
+     *
+     * @param telephonyServiceManager instance of {@link TelephonyServiceManager} that allows
+     * the telephony mainline module to register/obtain telephony binder services.
+     */
+    public static void setTelephonyServiceManager(
+            @NonNull TelephonyServiceManager telephonyServiceManager) {
+        Preconditions.checkState(sTelephonyServiceManager == null,
+                "setTelephonyServiceManager called twice!");
+        sTelephonyServiceManager = Preconditions.checkNotNull(telephonyServiceManager);
+    }
+
     /**
      * Called by {@link SystemServiceRegistry}'s static initializer and registers all telephony
      * services to {@link Context}, so that {@link Context#getSystemService} can return them.
@@ -68,4 +89,9 @@
                 context -> new EuiccCardManager(context)
         );
     }
+
+    /** @hide */
+    public static TelephonyServiceManager getTelephonyServiceManager() {
+        return sTelephonyServiceManager;
+    }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5b7ad12..5a4a3d0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -605,6 +605,7 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_EMERGENCY_ASSISTANCE =
             "android.telephony.action.EMERGENCY_ASSISTANCE";
@@ -5161,7 +5162,8 @@
     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private ITelephony getITelephony() {
-        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+        return ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
+                .getTelephonyServiceManager().getTelephonyServiceRegisterer().get());
     }
 
     private ITelephonyRegistry getTelephonyRegistry() {
@@ -9677,7 +9679,8 @@
      * {@link android.telephony.ModemActivityInfo} object.
      * @hide
      */
-    public void requestModemActivityInfo(ResultReceiver result) {
+    @SystemApi
+    public void requestModemActivityInfo(@NonNull ResultReceiver result) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
diff --git a/tests/ActivityManagerPerfTests/stub-app/Android.bp b/tests/ActivityManagerPerfTests/stub-app/Android.bp
new file mode 100644
index 0000000..a3c1f5b
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/Android.bp
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+    name: "ActivityManagerPerfTestsStubApp1",
+    static_libs: ["ActivityManagerPerfTestsUtils"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    resource_dirs: [
+        "app1/res",
+        "res",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    aaptflags: [
+        "--rename-manifest-package com.android.stubs.am1",
+        "--auto-add-overlay",
+    ],
+}
+
+android_test_helper_app {
+    name: "ActivityManagerPerfTestsStubApp2",
+    static_libs: ["ActivityManagerPerfTestsUtils"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    resource_dirs: [
+        "app2/res",
+        "res",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    aaptflags: [
+        "--rename-manifest-package com.android.stubs.am2",
+        "--auto-add-overlay",
+    ],
+}
+
+android_test_helper_app {
+    name: "ActivityManagerPerfTestsStubApp3",
+    static_libs: ["ActivityManagerPerfTestsUtils"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    resource_dirs: [
+        "app3/res",
+        "res",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    aaptflags: [
+        "--rename-manifest-package com.android.stubs.am3",
+        "--auto-add-overlay",
+    ],
+}
+
diff --git a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
new file mode 100644
index 0000000..a57f64c
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.stubs.am">
+
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
+    <application android:label="Android TestCase" >
+        <provider
+                android:authorities="@string/authority"
+                android:name=".TestContentProvider"
+                android:exported="true" />
+        <receiver
+                android:name=".TestBroadcastReceiver"
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </receiver>
+        <service
+                android:name=".InitService"
+                android:exported="true" />
+        <service
+                android:name=".TestService"
+                android:exported="true" />
+        <activity
+                android:name=".TestActivity"
+                android:excludeFromRecents="true"
+                android:turnScreenOn="true"
+                android:launchMode="singleTask">
+            <intent-filter>
+                <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml
new file mode 100644
index 0000000..667472d
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app1/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="authority" translatable="false">com.android.stubs.am1.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml
new file mode 100644
index 0000000..0852735
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app2/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="authority" translatable="false">com.android.stubs.am2.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml b/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml
new file mode 100644
index 0000000..6895d72
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/app3/res/values/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="authority" translatable="false">com.android.stubs.am3.testapp</string>
+</resources>
diff --git a/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml b/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml
new file mode 100644
index 0000000..f79f006
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/res/layout/activity_content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:id="@+id/content"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"/>
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java
new file mode 100644
index 0000000..18fdc44
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/InitService.java
@@ -0,0 +1,301 @@
+/*
+ * 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.stubs.am;
+
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_ACQUIRE_CONTENT_PROVIDER;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_BIND_SERVICE;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_RELEASE_CONTENT_PROVIDER;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_SEND_BROADCAST;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_START_ACTIVITY;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_STOP_ACTIVITY;
+import static com.android.frameworks.perftests.am.util.Constants.COMMAND_UNBIND_SERVICE;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.ICommandReceiver;
+
+public class InitService extends Service {
+    private static final String TAG = "InitService";
+    public static final boolean VERBOSE = false;
+
+    private static class Stub extends ICommandReceiver.Stub {
+        private final Context mContext;
+        private final Messenger mCallback;
+        private final Handler mHandler;
+        private final Messenger mMessenger;
+        final ArrayMap<String, MyServiceConnection> mServices =
+                new ArrayMap<String, MyServiceConnection>();
+        final ArrayMap<Uri, IContentProvider> mProviders =
+                new ArrayMap<Uri, IContentProvider>();
+
+        Stub(Context context, Messenger callback) {
+            mContext = context;
+            mCallback = callback;
+            HandlerThread thread = new HandlerThread("result handler");
+            thread.start();
+            mHandler = new H(thread.getLooper());
+            mMessenger = new Messenger(mHandler);
+        }
+
+        private class H extends Handler {
+            H(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == Constants.MSG_DEFAULT) {
+                    if (VERBOSE) {
+                        Log.i(TAG, "H: received seq=" + msg.arg1 + ", result=" + msg.arg2);
+                    }
+                    sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, msg.arg1, msg.arg2, null);
+                } else if (msg.what == Constants.MSG_UNBIND_DONE) {
+                    if (VERBOSE) {
+                        Log.i(TAG, "H: received unbind=" + msg.obj);
+                    }
+                    synchronized (InitService.sStub) {
+                        Bundle b = (Bundle) msg.obj;
+                        String pkg = b.getString(Constants.EXTRA_SOURCE_PACKAGE, "");
+                        MyServiceConnection c = mServices.remove(pkg);
+                        if (c != null) {
+                            sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq,
+                                    Constants.RESULT_NO_ERROR, null);
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void sendCommand(int command, int seq, String sourcePackage, String targetPackage,
+                int flags, Bundle bundle) {
+            if (VERBOSE) {
+                Log.i(TAG, "Received command=" + command + ", seq=" + seq + ", from="
+                        + sourcePackage + ", to=" + targetPackage + ", flags=" + flags);
+            }
+            switch (command) {
+                case COMMAND_BIND_SERVICE:
+                    handleBindService(seq, targetPackage, flags, bundle);
+                    break;
+                case COMMAND_UNBIND_SERVICE:
+                    handleUnbindService(seq, targetPackage);
+                    break;
+                case COMMAND_ACQUIRE_CONTENT_PROVIDER:
+                    acquireProvider(seq, bundle.getParcelable(Constants.EXTRA_URI));
+                    break;
+                case COMMAND_RELEASE_CONTENT_PROVIDER:
+                    releaseProvider(seq, bundle.getParcelable(Constants.EXTRA_URI));
+                    break;
+                case COMMAND_SEND_BROADCAST:
+                    sendBroadcast(seq, targetPackage);
+                    break;
+                case COMMAND_START_ACTIVITY:
+                    startActivity(seq, targetPackage);
+                    break;
+                case COMMAND_STOP_ACTIVITY:
+                    stopActivity(seq, targetPackage);
+                    break;
+            }
+        }
+
+        private void handleBindService(int seq, String targetPackage, int flags, Bundle bundle) {
+            Intent intent = new Intent();
+            intent.setClassName(targetPackage, "com.android.stubs.am.TestService");
+            intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+            if (bundle != null) {
+                intent.putExtras(bundle);
+            }
+            synchronized (this) {
+                if (!mServices.containsKey(targetPackage)) {
+                    MyServiceConnection c = new MyServiceConnection(mCallback);
+                    c.mSeq = seq;
+                    if (!mContext.bindService(intent, c, flags)) {
+                        Log.e(TAG, "Unable to bind to service in " + targetPackage);
+                        sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                                Constants.RESULT_ERROR, null);
+                    } else {
+                        if (VERBOSE) {
+                            Log.i(TAG, "Bind to service " + intent);
+                        }
+                        mServices.put(targetPackage, c);
+                    }
+                } else {
+                    sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                            Constants.RESULT_NO_ERROR, null);
+                }
+            }
+        }
+
+        private void handleUnbindService(int seq, String target) {
+            MyServiceConnection c = null;
+            synchronized (this) {
+                c = mServices.get(target);
+            }
+            if (c != null) {
+                c.mSeq = seq;
+                mContext.unbindService(c);
+            }
+        }
+
+        private void acquireProvider(int seq, Uri uri) {
+            ContentResolver resolver = mContext.getContentResolver();
+            IContentProvider provider = resolver.acquireProvider(uri);
+            if (provider != null) {
+                synchronized (mProviders) {
+                    mProviders.put(uri, provider);
+                }
+                sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                        Constants.RESULT_NO_ERROR, null);
+            } else {
+                sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                        Constants.RESULT_ERROR, null);
+            }
+        }
+
+        private void releaseProvider(int seq, Uri uri) {
+            ContentResolver resolver = mContext.getContentResolver();
+            IContentProvider provider;
+            synchronized (mProviders) {
+                provider = mProviders.get(uri);
+            }
+            if (provider != null) {
+                resolver.releaseProvider(provider);
+                synchronized (mProviders) {
+                    mProviders.remove(uri);
+                }
+            }
+            sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                    Constants.RESULT_NO_ERROR, null);
+        }
+
+        private void sendBroadcast(final int seq, String targetPackage) {
+            Intent intent = new Intent(Constants.STUB_ACTION_BROADCAST);
+            intent.setPackage(targetPackage);
+            mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq,
+                            Constants.RESULT_NO_ERROR, null);
+                }
+            }, null, 0, null, null);
+        }
+
+        private void startActivity(int seq, String targetPackage) {
+            Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY);
+            intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity");
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+            intent.putExtra(Constants.EXTRA_ARG1, seq);
+            intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+            mContext.startActivity(intent);
+        }
+
+        private void stopActivity(int seq, String targetPackage) {
+            Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY);
+            intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity");
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+            intent.putExtra(Constants.EXTRA_REQ_FINISH_ACTIVITY, true);
+            intent.putExtra(Constants.EXTRA_ARG1, seq);
+            intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger);
+            mContext.startActivity(intent);
+        }
+    };
+
+    private static void sendResult(Messenger callback, int what, int seq, int result, Object obj) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        msg.arg1 = seq;
+        msg.arg2 = result;
+        msg.obj = obj;
+        try {
+            if (VERBOSE) {
+                Log.i(TAG, "Sending result seq=" + seq + ", result=" + result);
+            }
+            callback.send(msg);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in sending result back", e);
+        }
+        msg.recycle();
+    }
+
+    private static class MyServiceConnection implements ServiceConnection {
+        private Messenger mCallback;
+        int mSeq;
+
+        MyServiceConnection(Messenger callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, mSeq,
+                    Constants.RESULT_NO_ERROR, null);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (sStub) {
+                MyServiceConnection c = sStub.mServices.remove(name.getPackageName());
+                if (c != null) {
+                    sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq,
+                            Constants.RESULT_NO_ERROR, null);
+                }
+            }
+        }
+    }
+
+    private static Stub sStub = null;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new Binder();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Messenger callback = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+        if (sStub == null) {
+            sStub = new Stub(getApplicationContext(), callback);
+        }
+
+        Bundle extras = new Bundle();
+        extras.putString(Constants.EXTRA_SOURCE_PACKAGE, getPackageName());
+        extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, sStub);
+        sendResult(callback, Constants.REPLY_PACKAGE_START_RESULT,
+                intent.getIntExtra(Constants.EXTRA_SEQ, -1), 0, extras);
+        return START_NOT_STICKY;
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java
new file mode 100644
index 0000000..f7ea356
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestActivity.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.stubs.am;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+public class TestActivity extends Activity {
+    private static final String TAG = "TestActivity";
+    private static final boolean VERBOSE = InitService.VERBOSE;
+
+    private Messenger mResultTo;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onCreate()");
+        }
+        setContentView(R.layout.activity_content);
+        mResultTo = getIntent().getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
+        mResultTo = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+        if (intent.getBooleanExtra(Constants.EXTRA_REQ_FINISH_ACTIVITY, false)) {
+            if (VERBOSE) {
+                Log.i(TAG, getPackageName() + " finishing activity");
+            }
+            finish();
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onResume()");
+        }
+        sendResult(Constants.RESULT_NO_ERROR);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onDestroy()");
+        }
+        sendResult(Constants.RESULT_NO_ERROR);
+    }
+
+    private void sendResult(int result) {
+        Message msg = Message.obtain();
+        msg.arg1 = getIntent().getIntExtra(Constants.EXTRA_ARG1, -1);
+        msg.arg2 = result;
+        try {
+            mResultTo.send(msg);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in sending result back", e);
+        }
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java
new file mode 100644
index 0000000..36c7a0a
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestBroadcastReceiver.java
@@ -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 com.android.stubs.am;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class TestBroadcastReceiver extends BroadcastReceiver {
+    private static final String TAG = "TestBroadcastReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.i(TAG, context.getPackageName() + " received broadcast: " + intent);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java
new file mode 100644
index 0000000..4fdbf1f
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestContentProvider.java
@@ -0,0 +1,62 @@
+/*
+ * 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.stubs.am;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+public class TestContentProvider extends ContentProvider {
+    private static final String TAG = "TestContentProvider";
+    private static final boolean VERBOSE = InitService.VERBOSE;
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public boolean onCreate() {
+        if (VERBOSE) {
+            Log.i(TAG, getContext().getPackageName() + " onCreate()");
+        }
+        return false;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java
new file mode 100644
index 0000000..ba220e0
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/stub-app/src/com/android/stubs/am/TestService.java
@@ -0,0 +1,71 @@
+/*
+ * 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.stubs.am;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+public class TestService extends Service {
+    private static final String TAG = "TestService";
+    private static final boolean VERBOSE = InitService.VERBOSE;
+
+    private Binder mStub = new Binder();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onBind()");
+        }
+        return mStub;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onStartCommand()");
+        }
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        if (VERBOSE) {
+            Log.i(TAG, getPackageName() + " onUnbind()");
+        }
+        Messenger messenger = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK);
+        Message msg = Message.obtain();
+        msg.what = Constants.MSG_UNBIND_DONE;
+        Bundle b = new Bundle();
+        b.putString(Constants.EXTRA_SOURCE_PACKAGE, getPackageName());
+        msg.obj = b;
+        try {
+            messenger.send(msg);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in sending result back", e);
+        }
+        return false;
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
index 76c40b2..475bb82 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -17,6 +17,9 @@
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="test-file-name" value="ActivityManagerPerfTests.apk"/>
         <option name="test-file-name" value="ActivityManagerPerfTestsTestApp.apk"/>
+        <option name="test-file-name" value="ActivityManagerPerfTestsStubApp1.apk"/>
+        <option name="test-file-name" value="ActivityManagerPerfTestsStubApp2.apk"/>
+        <option name="test-file-name" value="ActivityManagerPerfTestsStubApp3.apk"/>
         <option name="cleanup-apks" value="true"/>
     </target_preparer>
 
@@ -26,4 +29,4 @@
         <option name="package" value="com.android.frameworks.perftests.amtests"/>
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
new file mode 100644
index 0000000..1d3ff06
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.frameworks.perftests.am.tests;
+
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.HandlerThread;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkLine;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import com.android.frameworks.perftests.am.util.AtraceUtils;
+import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.Utils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This benchmark test basically manipulates 3 test packages, let them bind to
+ * each other, send broadcast to each other, etc. All of these actions essentially
+ * triggers OomAdjuster to update the oom_adj scores and proc state of them.
+ * In the meanwhile it'll also monitor the atrace output, extract duration between
+ * the start and exit entries of the updateOomAdjLocked, include each of them
+ * into the stats; when there are enough samples in the stats, the test will
+ * stop and output the mean/stddev time spent on the updateOomAdjLocked.
+ */
+@RunWith(JUnit4.class)
+@LargeTest
+public final class OomAdjPerfTest {
+    private static final String TAG = "OomAdjPerfTest";
+    private static final boolean VERBOSE = true;
+
+    private static final String STUB_PACKAGE1_NAME = "com.android.stubs.am1";
+    private static final String STUB_PACKAGE2_NAME = "com.android.stubs.am2";
+    private static final String STUB_PACKAGE3_NAME = "com.android.stubs.am3";
+
+    private static final Uri STUB_PACKAGE1_URI = new Uri.Builder().scheme(
+            ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am1.testapp").build();
+    private static final Uri STUB_PACKAGE2_URI = new Uri.Builder().scheme(
+            ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am2.testapp").build();
+    private static final Uri STUB_PACKAGE3_URI = new Uri.Builder().scheme(
+            ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am3.testapp").build();
+    private static final long NANOS_PER_MICROSECOND = 1000L;
+
+    private static final String ATRACE_CATEGORY = "am";
+    private static final String ATRACE_OOMADJ_PREFIX = "updateOomAdj_";
+
+    @Rule
+    public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+    private TraceMarkParser mTraceMarkParser = new TraceMarkParser(this::shouldFilterTraceLine);
+    private final ArrayList<Long> mDurations = new ArrayList<Long>();
+    private Context mContext;
+    private HandlerThread mHandlerThread;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mHandlerThread = new HandlerThread("command receiver");
+        mHandlerThread.start();
+        TargetPackageUtils.initCommandResultReceiver(mHandlerThread.getLooper());
+
+        Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE1_NAME);
+        Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE2_NAME);
+        Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE3_NAME);
+        TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE1_NAME);
+        TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE2_NAME);
+        TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE3_NAME);
+    }
+
+    @After
+    public void tearDown() {
+        TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE1_NAME);
+        TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE2_NAME);
+        TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE3_NAME);
+        Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE1_NAME);
+        Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE2_NAME);
+        Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE3_NAME);
+        mHandlerThread.quitSafely();
+    }
+
+    @Test
+    public void testOomAdj() {
+        final AtraceUtils atraceUtils = AtraceUtils.getInstance(
+                InstrumentationRegistry.getInstrumentation());
+        final ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState();
+        atraceUtils.startTrace(ATRACE_CATEGORY);
+        while (state.keepRunning(mDurations)) {
+            runCUJWithOomComputationOnce();
+
+            // Now kick off the trace dump
+            mDurations.clear();
+            atraceUtils.performDump(mTraceMarkParser, this::handleTraceMarkSlices);
+        }
+        atraceUtils.stopTrace();
+    }
+
+    private boolean shouldFilterTraceLine(final TraceMarkLine line) {
+        return line.name.startsWith(ATRACE_OOMADJ_PREFIX);
+    }
+
+    private void handleTraceMarkSlices(String key, List<TraceMarkSlice> slices) {
+        for (TraceMarkSlice slice: slices) {
+            mDurations.add(slice.getDurationInMicroseconds() * NANOS_PER_MICROSECOND);
+        }
+    }
+
+    /**
+     * This tries to mimic a user journey, involes multiple activity/service starts/stop,
+     * the time spent on oom adj computation would be different between all these samples,
+     * but with enough samples, we'll be able to know the overall distribution of the time
+     * spent on it.
+     */
+    private void runCUJWithOomComputationOnce() {
+        // Start activity from package1
+        TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+        // Start activity from package2
+        TargetPackageUtils.startActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+        // Start activity from package3
+        TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+        // Stop activity in package1
+        TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+        // Stop activity in package2
+        TargetPackageUtils.stopActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+        // Stop activity in package3
+        TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+        // Bind from package1 to package2
+        TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE);
+        // Acquire content provider from package 1 to package3
+        TargetPackageUtils.acquireProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
+                STUB_PACKAGE3_URI);
+        // Start activity from package1
+        TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+        // Bind from package2 to package3
+        TargetPackageUtils.bindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME,
+                Context.BIND_AUTO_CREATE);
+        // Unbind from package 1 to package 2
+        TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
+        // Stop activity in package1
+        TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+
+        // Send broadcast to all of them
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+        // Bind from package1 to package2 again
+        TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE);
+        // Create a cycle: package3 to package1
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
+                Context.BIND_AUTO_CREATE);
+
+        // Send broadcast to all of them again
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
+        TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+        // Start activity in package3
+        TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+
+        // Break the cycle: unbind from package3 to package1
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
+
+        // Bind from package3 to package1 with waive priority
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
+        // Release provider connection
+        TargetPackageUtils.releaseProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
+                STUB_PACKAGE3_URI);
+        // Unbind from package1 to package2
+        TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
+        // Unbind from package2 to packagae3
+        TargetPackageUtils.unbindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME, 0);
+
+        // Bind from package3 to package2 with BIND_ABOVE_CLIENT
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_ABOVE_CLIENT);
+        // Unbind from package3 to packagae2
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+        // Bind from package3 to package2 with BIND_ALLOW_OOM_MANAGEMENT
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT);
+        // Unbind from package3 to packagae2
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+        // Bind from package3 to package2 with BIND_IMPORTANT
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+        // Unbind from package3 to packagae2
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+        // Bind from package3 to package2 with BIND_NOT_FOREGROUND
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
+        // Unbind from package3 to packagae2
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+        // Bind from package3 to package2 with BIND_NOT_PERCEPTIBLE
+        TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
+                Context.BIND_AUTO_CREATE | Context.BIND_NOT_PERCEPTIBLE);
+        // Unbind from package3 to packagae2
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
+
+        // Stop activity in package3
+        TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
+        // Unbind from package3 to package1
+        TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java
new file mode 100644
index 0000000..fcccfce
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/AtraceUtils.java
@@ -0,0 +1,108 @@
+/*
+ * 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.frameworks.perftests.am.util;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+// Simplified version of AtraceLogger.
+public class AtraceUtils {
+    private static final String TAG = "AtraceUtils";
+    private static final boolean VERBOSE = true;
+
+    private static final String ATRACE_START = "atrace --async_start -b %d -c %s";
+    private static final String ATRACE_DUMP = "atrace --async_dump";
+    private static final String ATRACE_STOP = "atrace --async_stop";
+    private static final int DEFAULT_ATRACE_BUF_SIZE = 1024;
+
+    private UiAutomation mAutomation;
+    private static AtraceUtils sUtils = null;
+    private boolean mStarted = false;
+
+    private AtraceUtils(Instrumentation instrumentation) {
+        mAutomation = instrumentation.getUiAutomation();
+    }
+
+    public static AtraceUtils getInstance(Instrumentation instrumentation) {
+        if (sUtils == null) {
+            sUtils = new AtraceUtils(instrumentation);
+        }
+        return sUtils;
+    }
+
+    /**
+     * @param categories The list of the categories to trace, separated with space.
+     */
+    public void startTrace(String categories) {
+        synchronized (this) {
+            if (mStarted) {
+                throw new IllegalStateException("atrace already started");
+            }
+            Utils.runShellCommand(String.format(
+                    ATRACE_START, DEFAULT_ATRACE_BUF_SIZE, categories));
+            mStarted = true;
+        }
+    }
+
+    public void stopTrace() {
+        synchronized (this) {
+            mStarted = false;
+            Utils.runShellCommand(ATRACE_STOP);
+        }
+    }
+
+    /**
+     * @param parser The function that can accept the buffer of atrace dump and parse it.
+     * @param handler The parse result handler
+     */
+    public void performDump(TraceMarkParser parser,
+            BiConsumer<String, List<TraceMarkSlice>> handler) {
+        parser.reset();
+        try {
+            if (VERBOSE) {
+                Log.i(TAG, "Collecting atrace dump...");
+            }
+            writeDataToBuf(mAutomation.executeShellCommand(ATRACE_DUMP), parser);
+        } catch (IOException e) {
+            Log.e(TAG, "Error in reading dump", e);
+        }
+        parser.forAllSlices(handler);
+    }
+
+    // The given file descriptor here will be closed by this function
+    private void writeDataToBuf(ParcelFileDescriptor pfDescriptor,
+            TraceMarkParser parser) throws IOException {
+        InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfDescriptor);
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                parser.visit(line);
+            }
+        }
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
index 046dd6b..d7f4d9d 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
@@ -22,12 +22,18 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.ResultReceiver;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
 
 import org.junit.Assert;
 
@@ -36,6 +42,7 @@
 
 public class TargetPackageUtils {
     private static final String TAG = TargetPackageUtils.class.getSimpleName();
+    public static final boolean VERBOSE = true;
 
     public static final String PACKAGE_NAME = "com.android.frameworks.perftests.amteststestapp";
     public static final String ACTIVITY_NAME = PACKAGE_NAME + ".TestActivity";
@@ -48,6 +55,12 @@
     // Cache for test app's uid, so we only have to query it once.
     private static int sTestAppUid = -1;
 
+    private static final ArrayMap<String, ICommandReceiver> sStubPackages =
+            new ArrayMap<String, ICommandReceiver>();
+    private static final ArrayMap<Integer, CountDownLatch> sCommandLatches =
+            new ArrayMap<Integer, CountDownLatch>();
+    private static int sSeqNum = 0;
+
     /**
      * Kills the test package synchronously.
      */
@@ -145,5 +158,160 @@
         }
     }
 
+    private static boolean isUidRunning(int uid) {
+        return !Utils.runShellCommand(String.format("cmd activity get-uid-state %d", uid))
+                .contains("(NONEXISTENT)");
+    }
+
+    public static void startStubPackage(Context context, String pkgName) {
+        stopStubPackage(context, pkgName);
+        try {
+            Pair<Integer, CountDownLatch> pair = obtainLatch();
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName(pkgName, Constants.STUB_INIT_SERVICE_NAME));
+            intent.putExtra(Constants.EXTRA_SOURCE_PACKAGE, context.getPackageName());
+            intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, sMessenger);
+            intent.putExtra(Constants.EXTRA_SEQ, pair.first);
+            context.startService(intent);
+            Assert.assertTrue("Timeout when waiting for starting package " +  pkgName,
+                    pair.second.await(AWAIT_SERVICE_CONNECT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void stopStubPackage(Context context, String pkgName) {
+        final PackageManager pm = context.getPackageManager();
+        try {
+            final int uid = pm.getPackageUid(pkgName, 0);
+            if (isUidRunning(uid)) {
+                ActivityManager am = context.getSystemService(ActivityManager.class);
+                am.forceStopPackage(pkgName);
+                while (isUidRunning(uid)) {
+                    SystemClock.sleep(WAIT_TIME_MS);
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void initCommandResultReceiver(Looper looper) {
+        if (sMessenger == null) {
+            sMessenger = new Messenger(new H(looper));
+        }
+    }
+
+    private static void onPackageStartResult(int seq, Bundle bundle) {
+        ICommandReceiver receiver = ICommandReceiver.Stub.asInterface(
+                bundle.getBinder(Constants.EXTRA_RECEIVER_CALLBACK));
+        String sourcePkg = bundle.getString(Constants.EXTRA_SOURCE_PACKAGE);
+        sStubPackages.put(sourcePkg, receiver);
+        releaseLatch(seq);
+    }
+
+    private static void onCommandResult(int seq, int result) {
+        Assert.assertTrue("Error in command seq " + seq, result == Constants.RESULT_NO_ERROR);
+        releaseLatch(seq);
+    }
+
+    private static Messenger sMessenger = null;
+    private static class H extends Handler {
+        H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case Constants.REPLY_PACKAGE_START_RESULT:
+                    onPackageStartResult(msg.arg1 /* seq */, (Bundle) msg.obj);
+                    break;
+                case Constants.REPLY_COMMAND_RESULT:
+                    onCommandResult(msg.arg1, msg.arg2);
+                    break;
+            }
+        }
+    }
+
+    private static Pair<Integer, CountDownLatch> obtainLatch() {
+        CountDownLatch latch = new CountDownLatch(1);
+        int seq;
+        synchronized (sCommandLatches) {
+            seq = sSeqNum++;
+            sCommandLatches.put(seq, latch);
+        }
+        return new Pair<>(seq, latch);
+    }
+
+    private static void releaseLatch(int seq) {
+        synchronized (sCommandLatches) {
+            CountDownLatch latch = sCommandLatches.get(seq);
+            if (latch != null) {
+                latch.countDown();
+                sCommandLatches.remove(seq);
+            }
+        }
+    }
+
+    public static void sendCommand(int command, String sourcePackage, String targetPackage,
+            int flags, Bundle bundle, boolean waitForResult) {
+        ICommandReceiver receiver = sStubPackages.get(sourcePackage);
+        Assert.assertTrue("Package hasn't been started: " + sourcePackage, receiver != null);
+        try {
+            Pair<Integer, CountDownLatch> pair = null;
+            if (waitForResult) {
+                pair = obtainLatch();
+            }
+            if (VERBOSE) {
+                Log.i(TAG, "Sending command=" + command + ", seq=" + pair.first + ", from="
+                        + sourcePackage + ", to=" + targetPackage + ", flags=" + flags);
+            }
+            receiver.sendCommand(command, pair.first, sourcePackage, targetPackage, flags, bundle);
+            if (waitForResult) {
+                Assert.assertTrue("Timeout when waiting for command " + command + " from "
+                        + sourcePackage + " to " + targetPackage,
+                        pair.second.await(AWAIT_SERVICE_CONNECT_MS, TimeUnit.MILLISECONDS));
+            }
+        } catch (RemoteException | InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void bindService(String sourcePackage, String targetPackage, int flags) {
+        sendCommand(Constants.COMMAND_BIND_SERVICE, sourcePackage, targetPackage, flags, null,
+                true);
+    }
+
+    public static void unbindService(String sourcePackage, String targetPackage, int flags) {
+        sendCommand(Constants.COMMAND_UNBIND_SERVICE, sourcePackage, targetPackage, flags, null,
+                true);
+    }
+
+    public static void acquireProvider(String sourcePackage, String targetPackage, Uri uri) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(Constants.EXTRA_URI, uri);
+        sendCommand(Constants.COMMAND_ACQUIRE_CONTENT_PROVIDER, sourcePackage, targetPackage, 0,
+                bundle, true);
+    }
+
+    public static void releaseProvider(String sourcePackage, String targetPackage, Uri uri) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(Constants.EXTRA_URI, uri);
+        sendCommand(Constants.COMMAND_RELEASE_CONTENT_PROVIDER, sourcePackage, targetPackage, 0,
+                bundle, true);
+    }
+
+    public static void sendBroadcast(String sourcePackage, String targetPackage) {
+        sendCommand(Constants.COMMAND_SEND_BROADCAST, sourcePackage, targetPackage, 0, null, true);
+    }
+
+    public static void startActivity(String sourcePackage, String targetPackage) {
+        sendCommand(Constants.COMMAND_START_ACTIVITY, sourcePackage, targetPackage, 0, null, true);
+    }
+
+    public static void stopActivity(String sourcePackage, String targetPackage) {
+        sendCommand(Constants.COMMAND_STOP_ACTIVITY, sourcePackage, targetPackage, 0, null, true);
+    }
 }
 
diff --git a/tests/ActivityManagerPerfTests/utils/Android.bp b/tests/ActivityManagerPerfTests/utils/Android.bp
index 300b7ea..766c3ac 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.bp
+++ b/tests/ActivityManagerPerfTests/utils/Android.bp
@@ -18,6 +18,7 @@
     srcs: [
         "src/**/*.java",
         "src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl",
+        "src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl",
     ],
     static_libs: [
         "androidx.test.rules",
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
index 9b076c5..8e58665 100644
--- a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
@@ -30,4 +30,33 @@
 
     public static final String EXTRA_RECEIVER_CALLBACK = "receiver_callback_binder";
     public static final String EXTRA_LOOPER_IDLE_CALLBACK = "looper_idle_callback_binder";
+    public static final String EXTRA_SOURCE_PACKAGE = "source_package";
+    public static final String EXTRA_URI = "uri";
+    public static final String EXTRA_REQ_FINISH_ACTIVITY = "req_finish_activity";
+    public static final String EXTRA_SEQ = "seq";
+    public static final String EXTRA_ARG1 = "arg1";
+    public static final String EXTRA_ARG2 = "arg2";
+
+    public static final int RESULT_NO_ERROR = 0;
+    public static final int RESULT_ERROR = 1;
+    public static final String STUB_INIT_SERVICE_NAME = "com.android.stubs.am.InitService";
+
+    public static final int COMMAND_BIND_SERVICE = 1;
+    public static final int COMMAND_UNBIND_SERVICE = 2;
+    public static final int COMMAND_ACQUIRE_CONTENT_PROVIDER = 3;
+    public static final int COMMAND_RELEASE_CONTENT_PROVIDER = 4;
+    public static final int COMMAND_SEND_BROADCAST = 5;
+    public static final int COMMAND_START_ACTIVITY = 6;
+    public static final int COMMAND_STOP_ACTIVITY = 7;
+
+    public static final int MSG_DEFAULT = 0;
+    public static final int MSG_UNBIND_DONE = 1;
+
+    public static final int REPLY_PACKAGE_START_RESULT = 0;
+    public static final int REPLY_COMMAND_RESULT = 1;
+
+    public static final String STUB_ACTION_ACTIVITY =
+            "com.android.stubs.am.ACTION_START_TEST_ACTIVITY";
+    public static final String STUB_ACTION_BROADCAST =
+            "com.android.stubs.am.ACTION_BROADCAST_TEST";
 }
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl
new file mode 100644
index 0000000..59ea761
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/ICommandReceiver.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.frameworks.perftests.am.util;
+
+import android.os.Bundle;
+
+interface ICommandReceiver {
+    oneway void sendCommand(int command, int seq, String sourcePackage, String targetPackage,
+            int flags, in Bundle bundle);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index b52880e..1678d5a 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -108,7 +108,9 @@
 
     String getCountryCode();
 
-    boolean isDualBandSupported();
+    boolean is5GHzBandSupported();
+
+    boolean is6GHzBandSupported();
 
     boolean needs5GHzToAnyApBandConversion();
 
@@ -186,7 +188,7 @@
 
     byte[] retrieveSoftApBackupData();
 
-    void restoreSoftApBackupData(in byte[] data);
+    SoftApConfiguration restoreSoftApBackupData(in byte[] data);
 
     void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
 
diff --git a/wifi/java/android/net/wifi/WifiCondManager.java b/wifi/java/android/net/wifi/WifiCondManager.java
new file mode 100644
index 0000000..9ae7e3a
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiCondManager.java
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.net.wifi.wificond.ChannelSettings;
+import android.net.wifi.wificond.HiddenNetwork;
+import android.net.wifi.wificond.NativeScanResult;
+import android.net.wifi.wificond.NativeWifiClient;
+import android.net.wifi.wificond.PnoSettings;
+import android.net.wifi.wificond.SingleScanSettings;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class provides methods for WifiNative to send control commands to wificond.
+ * NOTE: This class should only be used from WifiNative.
+ * @hide
+ */
+public class WifiCondManager implements IBinder.DeathRecipient {
+    private static final String TAG = "WifiCondManager";
+    private boolean mVerboseLoggingEnabled = false;
+
+    /**
+     * The {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * timeout, in milliseconds, after which
+     * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
+     * {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}.
+     */
+    public static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
+
+    private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SCAN_TYPE_"},
+            value = {SCAN_TYPE_SINGLE_SCAN,
+                    SCAN_TYPE_PNO_SCAN})
+    public @interface ScanResultType {}
+
+    /** Get scan results for a single scan */
+    public static final int SCAN_TYPE_SINGLE_SCAN = 0;
+
+    /** Get scan results for Pno Scan */
+    public static final int SCAN_TYPE_PNO_SCAN = 1;
+
+    private AlarmManager mAlarmManager;
+    private Handler mEventHandler;
+
+    // Cached wificond binder handlers.
+    private IWificond mWificond;
+    private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
+    private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
+    private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>();
+    private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>();
+    private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>();
+    private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>();
+    private Runnable mDeathEventHandler;
+    /**
+     * Ensures that no more than one sendMgmtFrame operation runs concurrently.
+     */
+    private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
+
+    /**
+     * Interface for a callback to be used to handle scan results.
+     */
+    public interface ScanEventCallback {
+        /**
+         * Called when scan results are available.
+         */
+        void onScanResultReady();
+
+        /**
+         * Called when a scan has failed.
+         */
+        void onScanFailed();
+    }
+
+    /**
+     * Interface for a callback to provide information about PNO scan request.
+     */
+    public interface PnoScanRequestCallback {
+        /**
+         * Called when the PNO scan is requested.
+         */
+        void onPnoRequestSucceeded();
+
+        /**
+         * Called when a PNO scan request fails.
+         */
+        void onPnoRequestFailed();
+    }
+
+    private class ScanEventHandler extends IScanEvent.Stub {
+        private ScanEventCallback mCallback;
+
+        ScanEventHandler(@NonNull ScanEventCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void OnScanResultReady() {
+            Log.d(TAG, "Scan result ready event");
+            mCallback.onScanResultReady();
+        }
+
+        @Override
+        public void OnScanFailed() {
+            Log.d(TAG, "Scan failed event");
+            mCallback.onScanFailed();
+        }
+    }
+
+    /**
+     * Result of a signal poll.
+     */
+    public static class SignalPollResult {
+        // RSSI value in dBM.
+        public int currentRssi;
+        //Transmission bit rate in Mbps.
+        public int txBitrate;
+        // Association frequency in MHz.
+        public int associationFrequency;
+        //Last received packet bit rate in Mbps.
+        public int rxBitrate;
+    }
+
+    /**
+     * WiFi interface transimission counters.
+     */
+    public static class TxPacketCounters {
+        // Number of successfully transmitted packets.
+        public int txSucceeded;
+        // Number of tramsmission failures.
+        public int txFailed;
+    }
+
+    /**
+     * Callbacks for SoftAp interface.
+     */
+    public interface SoftApListener {
+        /**
+         * Invoked when there is some fatal failure in the lower layers.
+         */
+        void onFailure();
+
+        /**
+         * Invoked when the associated stations changes.
+         */
+        void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected);
+
+        /**
+         * Invoked when the channel switch event happens.
+         */
+        void onSoftApChannelSwitched(int frequency, int bandwidth);
+    }
+
+    /**
+     * Callback to notify the results of a
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} call.
+     * Note: no callbacks will be triggered if the iface dies while sending a frame.
+     */
+    public interface SendMgmtFrameCallback {
+        /**
+         * Called when the management frame was successfully sent and ACKed by the recipient.
+         * @param elapsedTimeMs The elapsed time between when the management frame was sent and when
+         *                      the ACK was processed, in milliseconds, as measured by wificond.
+         *                      This includes the time that the send frame spent queuing before it
+         *                      was sent, any firmware retries, and the time the received ACK spent
+         *                      queuing before it was processed.
+         */
+        void onAck(int elapsedTimeMs);
+
+        /**
+         * Called when the send failed.
+         * @param reason The error code for the failure.
+         */
+        void onFailure(@SendMgmtFrameError int reason);
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"},
+            value = {SEND_MGMT_FRAME_ERROR_UNKNOWN,
+                    SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED,
+                    SEND_MGMT_FRAME_ERROR_NO_ACK,
+                    SEND_MGMT_FRAME_ERROR_TIMEOUT,
+                    SEND_MGMT_FRAME_ERROR_ALREADY_STARTED})
+    public @interface SendMgmtFrameError {}
+
+    // Send management frame error codes
+
+    /**
+     * Unknown error occurred during call to
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
+     */
+    public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
+
+    /**
+     * Specifying the MCS rate in
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} is not
+     * supported by this device.
+     */
+    public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
+
+    /**
+     * Driver reported that no ACK was received for the frame transmitted using
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
+     */
+    public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
+
+    /**
+     * Error code for when the driver fails to report on the status of the frame sent by
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds.
+     */
+    public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
+
+    /**
+     * An existing call to
+     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * is in progress. Another frame cannot be sent until the first call completes.
+     */
+    public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
+
+
+    public WifiCondManager(Context context) {
+        mAlarmManager = (AlarmManager) context.getSystemService(AlarmManager.class);
+        mEventHandler = new Handler(context.getMainLooper());
+    }
+
+    @VisibleForTesting
+    public WifiCondManager(Context context, IWificond wificond) {
+        this(context);
+        mWificond = wificond;
+    }
+
+    private class PnoScanEventHandler extends IPnoScanEvent.Stub {
+        private ScanEventCallback mCallback;
+
+        PnoScanEventHandler(@NonNull ScanEventCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void OnPnoNetworkFound() {
+            Log.d(TAG, "Pno scan result event");
+            mCallback.onScanResultReady();
+        }
+
+        @Override
+        public void OnPnoScanFailed() {
+            Log.d(TAG, "Pno Scan failed event");
+            mCallback.onScanFailed();
+        }
+    }
+
+    /**
+     * Listener for AP Interface events.
+     */
+    private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
+        private SoftApListener mSoftApListener;
+
+        ApInterfaceEventCallback(SoftApListener listener) {
+            mSoftApListener = listener;
+        }
+
+        @Override
+        public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "onConnectedClientsChanged called with "
+                        + client.macAddress + " isConnected: " + isConnected);
+            }
+
+            mSoftApListener.onConnectedClientsChanged(client, isConnected);
+        }
+
+        @Override
+        public void onSoftApChannelSwitched(int frequency, int bandwidth) {
+            mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth);
+        }
+    }
+
+    /**
+     * Callback triggered by wificond.
+     */
+    private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
+        private SendMgmtFrameCallback mCallback;
+        private AlarmManager.OnAlarmListener mTimeoutCallback;
+        /**
+         * ensures that mCallback is only called once
+         */
+        private boolean mWasCalled;
+
+        private void runIfFirstCall(Runnable r) {
+            if (mWasCalled) return;
+            mWasCalled = true;
+
+            mSendMgmtFrameInProgress.set(false);
+            r.run();
+        }
+
+        SendMgmtFrameEvent(@NonNull SendMgmtFrameCallback callback) {
+            mCallback = callback;
+            // called in main thread
+            mTimeoutCallback = () -> runIfFirstCall(() -> {
+                if (mVerboseLoggingEnabled) {
+                    Log.e(TAG, "Timed out waiting for ACK");
+                }
+                mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT);
+            });
+            mWasCalled = false;
+
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() + SEND_MGMT_FRAME_TIMEOUT_MS,
+                    TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler);
+        }
+
+        // called in binder thread
+        @Override
+        public void OnAck(int elapsedTimeMs) {
+            // post to main thread
+            mEventHandler.post(() -> runIfFirstCall(() -> {
+                mAlarmManager.cancel(mTimeoutCallback);
+                mCallback.onAck(elapsedTimeMs);
+            }));
+        }
+
+        // called in binder thread
+        @Override
+        public void OnFailure(int reason) {
+            // post to main thread
+            mEventHandler.post(() -> runIfFirstCall(() -> {
+                mAlarmManager.cancel(mTimeoutCallback);
+                mCallback.onFailure(reason);
+            }));
+        }
+    }
+
+    /**
+     * Called by the binder subsystem upon remote object death.
+     * Invoke all the register death handlers and clear state.
+     */
+    @Override
+    public void binderDied() {
+        mEventHandler.post(() -> {
+            Log.e(TAG, "Wificond died!");
+            clearState();
+            // Invalidate the global wificond handle on death. Will be refreshed
+            // on the next setup call.
+            mWificond = null;
+            if (mDeathEventHandler != null) {
+                mDeathEventHandler.run();
+            }
+        });
+    }
+
+    /** Enable or disable verbose logging of WificondControl.
+     *  @param enable True to enable verbose logging. False to disable verbose logging.
+     */
+    public void enableVerboseLogging(boolean enable) {
+        mVerboseLoggingEnabled = enable;
+    }
+
+    /**
+     * Initializes wificond & registers a death notification for wificond.
+     * This method clears any existing state in wificond daemon.
+     *
+     * @return Returns true on success.
+     */
+    public boolean initialize(@NonNull Runnable deathEventHandler) {
+        if (mDeathEventHandler != null) {
+            Log.e(TAG, "Death handler already present");
+        }
+        mDeathEventHandler = deathEventHandler;
+        tearDownInterfaces();
+        return true;
+    }
+
+    /**
+     * Helper method to retrieve the global wificond handle and register for
+     * death notifications.
+     */
+    private boolean retrieveWificondAndRegisterForDeath() {
+        if (mWificond != null) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "Wificond handle already retrieved");
+            }
+            // We already have a wificond handle.
+            return true;
+        }
+        IBinder binder = ServiceManager.getService(Context.WIFI_COND_SERVICE);
+        mWificond = IWificond.Stub.asInterface(binder);
+        if (mWificond == null) {
+            Log.e(TAG, "Failed to get reference to wificond");
+            return false;
+        }
+        try {
+            mWificond.asBinder().linkToDeath(this, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register death notification for wificond");
+            // The remote has already died.
+            return false;
+        }
+        return true;
+    }
+
+    /**
+    * Setup interface for client mode via wificond.
+    * @return true on success.
+    */
+    public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
+            @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
+        Log.d(TAG, "Setting up interface for client mode");
+        if (!retrieveWificondAndRegisterForDeath()) {
+            return false;
+        }
+
+        IClientInterface clientInterface = null;
+        try {
+            clientInterface = mWificond.createClientInterface(ifaceName);
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to get IClientInterface due to remote exception");
+            return false;
+        }
+
+        if (clientInterface == null) {
+            Log.e(TAG, "Could not get IClientInterface instance from wificond");
+            return false;
+        }
+        Binder.allowBlocking(clientInterface.asBinder());
+
+        // Refresh Handlers
+        mClientInterfaces.put(ifaceName, clientInterface);
+        try {
+            IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
+            if (wificondScanner == null) {
+                Log.e(TAG, "Failed to get WificondScannerImpl");
+                return false;
+            }
+            mWificondScanners.put(ifaceName, wificondScanner);
+            Binder.allowBlocking(wificondScanner.asBinder());
+            ScanEventHandler scanEventHandler = new ScanEventHandler(scanCallback);
+            mScanEventHandlers.put(ifaceName,  scanEventHandler);
+            wificondScanner.subscribeScanEvents(scanEventHandler);
+            PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(pnoScanCallback);
+            mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
+            wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
+        }
+
+        return true;
+    }
+
+    /**
+     * Teardown a specific STA interface configured in wificond.
+     *
+     * @return Returns true on success.
+     */
+    public boolean tearDownClientInterface(@NonNull String ifaceName) {
+        if (getClientInterface(ifaceName) == null) {
+            Log.e(TAG, "No valid wificond client interface handler");
+            return false;
+        }
+        try {
+            IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName);
+            if (scannerImpl != null) {
+                scannerImpl.unsubscribeScanEvents();
+                scannerImpl.unsubscribePnoScanEvents();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception");
+            return false;
+        }
+
+        if (mWificond == null) {
+            Log.e(TAG, "Reference to wifiCond is null");
+            return false;
+        }
+
+        boolean success;
+        try {
+            success = mWificond.tearDownClientInterface(ifaceName);
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to teardown client interface due to remote exception");
+            return false;
+        }
+        if (!success) {
+            Log.e(TAG, "Failed to teardown client interface");
+            return false;
+        }
+
+        mClientInterfaces.remove(ifaceName);
+        mWificondScanners.remove(ifaceName);
+        mScanEventHandlers.remove(ifaceName);
+        mPnoScanEventHandlers.remove(ifaceName);
+        return true;
+    }
+
+    /**
+    * Setup interface for softAp mode via wificond.
+    * @return true on success.
+    */
+    public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) {
+        Log.d(TAG, "Setting up interface for soft ap mode");
+        if (!retrieveWificondAndRegisterForDeath()) {
+            return false;
+        }
+
+        IApInterface apInterface = null;
+        try {
+            apInterface = mWificond.createApInterface(ifaceName);
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to get IApInterface due to remote exception");
+            return false;
+        }
+
+        if (apInterface == null) {
+            Log.e(TAG, "Could not get IApInterface instance from wificond");
+            return false;
+        }
+        Binder.allowBlocking(apInterface.asBinder());
+
+        // Refresh Handlers
+        mApInterfaces.put(ifaceName, apInterface);
+        return true;
+    }
+
+    /**
+     * Teardown a specific AP interface configured in wificond.
+     *
+     * @return Returns true on success.
+     */
+    public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
+        if (getApInterface(ifaceName) == null) {
+            Log.e(TAG, "No valid wificond ap interface handler");
+            return false;
+        }
+
+        if (mWificond == null) {
+            Log.e(TAG, "Reference to wifiCond is null");
+            return false;
+        }
+
+        boolean success;
+        try {
+            success = mWificond.tearDownApInterface(ifaceName);
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to teardown AP interface due to remote exception");
+            return false;
+        }
+        if (!success) {
+            Log.e(TAG, "Failed to teardown AP interface");
+            return false;
+        }
+        mApInterfaces.remove(ifaceName);
+        mApInterfaceListeners.remove(ifaceName);
+        return true;
+    }
+
+    /**
+    * Teardown all interfaces configured in wificond.
+    * @return Returns true on success.
+    */
+    public boolean tearDownInterfaces() {
+        Log.d(TAG, "tearing down interfaces in wificond");
+        // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
+        // could be used to cleanup before we setup any interfaces.
+        if (!retrieveWificondAndRegisterForDeath()) {
+            return false;
+        }
+
+        try {
+            for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) {
+                entry.getValue().unsubscribeScanEvents();
+                entry.getValue().unsubscribePnoScanEvents();
+            }
+            mWificond.tearDownInterfaces();
+            clearState();
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to tear down interfaces due to remote exception");
+        }
+
+        return false;
+    }
+
+    /** Helper function to look up the interface handle using name */
+    private IClientInterface getClientInterface(@NonNull String ifaceName) {
+        return mClientInterfaces.get(ifaceName);
+    }
+
+    /**
+     * Request signal polling to wificond.
+     * @param ifaceName Name of the interface.
+     * Returns an SignalPollResult object.
+     * Returns null on failure.
+     */
+    public SignalPollResult signalPoll(@NonNull String ifaceName) {
+        IClientInterface iface = getClientInterface(ifaceName);
+        if (iface == null) {
+            Log.e(TAG, "No valid wificond client interface handler");
+            return null;
+        }
+
+        int[] resultArray;
+        try {
+            resultArray = iface.signalPoll();
+            if (resultArray == null || resultArray.length != 4) {
+                Log.e(TAG, "Invalid signal poll result from wificond");
+                return null;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to do signal polling due to remote exception");
+            return null;
+        }
+        SignalPollResult pollResult = new SignalPollResult();
+        pollResult.currentRssi = resultArray[0];
+        pollResult.txBitrate = resultArray[1];
+        pollResult.associationFrequency = resultArray[2];
+        pollResult.rxBitrate = resultArray[3];
+        return pollResult;
+    }
+
+    /**
+     * Fetch TX packet counters on current connection from wificond.
+     * @param ifaceName Name of the interface.
+     * Returns an TxPacketCounters object.
+     * Returns null on failure.
+     */
+    public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
+        IClientInterface iface = getClientInterface(ifaceName);
+        if (iface == null) {
+            Log.e(TAG, "No valid wificond client interface handler");
+            return null;
+        }
+
+        int[] resultArray;
+        try {
+            resultArray = iface.getPacketCounters();
+            if (resultArray == null || resultArray.length != 2) {
+                Log.e(TAG, "Invalid signal poll result from wificond");
+                return null;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to do signal polling due to remote exception");
+            return null;
+        }
+        TxPacketCounters counters = new TxPacketCounters();
+        counters.txSucceeded = resultArray[0];
+        counters.txFailed = resultArray[1];
+        return counters;
+    }
+
+    /** Helper function to look up the scanner impl handle using name */
+    private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) {
+        return mWificondScanners.get(ifaceName);
+    }
+
+    /**
+    * Fetch the latest scan result from kernel via wificond.
+    * @param ifaceName Name of the interface.
+    * @return Returns an array of native scan results or an empty array on failure.
+    */
+    @NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
+            @ScanResultType int scanType) {
+        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+        if (scannerImpl == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return new ArrayList<>();
+        }
+        List<NativeScanResult> results = null;
+        try {
+            if (scanType == SCAN_TYPE_SINGLE_SCAN) {
+                results = Arrays.asList(scannerImpl.getScanResults());
+            } else {
+                results = Arrays.asList(scannerImpl.getPnoScanResults());
+            }
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to create ScanDetail ArrayList");
+        }
+        if (results == null) {
+            results = new ArrayList<>();
+        }
+        if (mVerboseLoggingEnabled) {
+            Log.d(TAG, "get " + results.size() + " scan results from wificond");
+        }
+
+        return results;
+    }
+
+    /**
+     * Return scan type for the parcelable {@link SingleScanSettings}
+     */
+    private static int getScanType(@WifiScanner.ScanType int scanType) {
+        switch (scanType) {
+            case WifiScanner.SCAN_TYPE_LOW_LATENCY:
+                return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN;
+            case WifiScanner.SCAN_TYPE_LOW_POWER:
+                return IWifiScannerImpl.SCAN_TYPE_LOW_POWER;
+            case WifiScanner.SCAN_TYPE_HIGH_ACCURACY:
+                return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+            default:
+                throw new IllegalArgumentException("Invalid scan type " + scanType);
+        }
+    }
+
+    /**
+     * Start a scan using wificond for the given parameters.
+     * @param ifaceName Name of the interface.
+     * @param scanType Type of scan to perform.
+     * @param freqs list of frequencies to scan for, if null scan all supported channels.
+     * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
+     * @return Returns true on success.
+     */
+    public boolean scan(@NonNull String ifaceName, @WifiScanner.ScanType int scanType,
+            Set<Integer> freqs, List<byte[]> hiddenNetworkSSIDs) {
+        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+        if (scannerImpl == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return false;
+        }
+        SingleScanSettings settings = new SingleScanSettings();
+        try {
+            settings.scanType = getScanType(scanType);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Invalid scan type ", e);
+            return false;
+        }
+        settings.channelSettings  = new ArrayList<>();
+        settings.hiddenNetworks  = new ArrayList<>();
+
+        if (freqs != null) {
+            for (Integer freq : freqs) {
+                ChannelSettings channel = new ChannelSettings();
+                channel.frequency = freq;
+                settings.channelSettings.add(channel);
+            }
+        }
+        if (hiddenNetworkSSIDs != null) {
+            for (byte[] ssid : hiddenNetworkSSIDs) {
+                HiddenNetwork network = new HiddenNetwork();
+                network.ssid = ssid;
+
+                // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
+                // any performance issues.
+                if (!settings.hiddenNetworks.contains(network)) {
+                    settings.hiddenNetworks.add(network);
+                }
+            }
+        }
+
+        try {
+            return scannerImpl.scan(settings);
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to request scan due to remote exception");
+        }
+        return false;
+    }
+
+    /**
+     * Start PNO scan.
+     * @param ifaceName Name of the interface.
+     * @param pnoSettings Pno scan configuration.
+     * @return true on success.
+     */
+    public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings,
+            PnoScanRequestCallback callback) {
+        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+        if (scannerImpl == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return false;
+        }
+
+        try {
+            boolean success = scannerImpl.startPnoScan(pnoSettings);
+            if (success) {
+                callback.onPnoRequestSucceeded();
+            } else {
+                callback.onPnoRequestFailed();
+            }
+            return success;
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to start pno scan due to remote exception");
+        }
+        return false;
+    }
+
+    /**
+     * Stop PNO scan.
+     * @param ifaceName Name of the interface.
+     * @return true on success.
+     */
+    public boolean stopPnoScan(@NonNull String ifaceName) {
+        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+        if (scannerImpl == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return false;
+        }
+        try {
+            return scannerImpl.stopPnoScan();
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to stop pno scan due to remote exception");
+        }
+        return false;
+    }
+
+    /**
+     * Abort ongoing single scan.
+     * @param ifaceName Name of the interface.
+     */
+    public void abortScan(@NonNull String ifaceName) {
+        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+        if (scannerImpl == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return;
+        }
+        try {
+            scannerImpl.abortScan();
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to request abortScan due to remote exception");
+        }
+    }
+
+    /**
+     * Query the list of valid frequencies for the provided band.
+     * The result depends on the on the country code that has been set.
+     *
+     * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
+     * The following bands are supported {@link @WifiScanner.WifiBandBasic}:
+     * WifiScanner.WIFI_BAND_24_GHZ
+     * WifiScanner.WIFI_BAND_5_GHZ
+     * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
+     * WifiScanner.WIFI_BAND_6_GHZ
+     * @return frequencies vector of valid frequencies (MHz), or null for error.
+     * @throws IllegalArgumentException if band is not recognized.
+     */
+    public int [] getChannelsForBand(@WifiScanner.WifiBandBasic int band) {
+        if (mWificond == null) {
+            Log.e(TAG, "No valid wificond scanner interface handler");
+            return null;
+        }
+        try {
+            switch (band) {
+                case WifiScanner.WIFI_BAND_24_GHZ:
+                    return mWificond.getAvailable2gChannels();
+                case WifiScanner.WIFI_BAND_5_GHZ:
+                    return mWificond.getAvailable5gNonDFSChannels();
+                case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
+                    return mWificond.getAvailableDFSChannels();
+                case WifiScanner.WIFI_BAND_6_GHZ:
+                    return mWificond.getAvailable6gChannels();
+                default:
+                    throw new IllegalArgumentException("unsupported band " + band);
+            }
+        } catch (RemoteException e1) {
+            Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
+        }
+        return null;
+    }
+
+    /** Helper function to look up the interface handle using name */
+    private IApInterface getApInterface(@NonNull String ifaceName) {
+        return mApInterfaces.get(ifaceName);
+    }
+
+    /**
+     * Register the provided listener for SoftAp events.
+     *
+     * @param ifaceName Name of the interface.
+     * @param listener Callback for AP events.
+     * @return true on success, false otherwise.
+     */
+    public boolean registerApListener(@NonNull String ifaceName, SoftApListener listener) {
+        IApInterface iface = getApInterface(ifaceName);
+        if (iface == null) {
+            Log.e(TAG, "No valid ap interface handler");
+            return false;
+        }
+        try {
+            IApInterfaceEventCallback  callback = new ApInterfaceEventCallback(listener);
+            mApInterfaceListeners.put(ifaceName, callback);
+            boolean success = iface.registerCallback(callback);
+            if (!success) {
+                Log.e(TAG, "Failed to register ap callback.");
+                return false;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception in registering AP callback: " + e);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * See {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int)}
+     */
+    public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
+            @NonNull SendMgmtFrameCallback callback, int mcs) {
+
+        if (callback == null) {
+            Log.e(TAG, "callback cannot be null!");
+            return;
+        }
+
+        if (frame == null) {
+            Log.e(TAG, "frame cannot be null!");
+            callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+            return;
+        }
+
+        // TODO (b/112029045) validate mcs
+        IClientInterface clientInterface = getClientInterface(ifaceName);
+        if (clientInterface == null) {
+            Log.e(TAG, "No valid wificond client interface handler");
+            callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+            return;
+        }
+
+        if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
+            Log.e(TAG, "An existing management frame transmission is in progress!");
+            callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
+            return;
+        }
+
+        SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(callback);
+        try {
+            clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception while starting link probe: " + e);
+            // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that
+            // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer.
+            sendMgmtFrameEvent.OnFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+        }
+    }
+
+    /**
+     * Clear all internal handles.
+     */
+    private void clearState() {
+        // Refresh handlers
+        mClientInterfaces.clear();
+        mWificondScanners.clear();
+        mPnoScanEventHandlers.clear();
+        mScanEventHandlers.clear();
+        mApInterfaces.clear();
+        mApInterfaceListeners.clear();
+        mSendMgmtFrameInProgress.set(false);
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 50d62a0..9691bda 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -51,16 +51,16 @@
 import android.os.WorkSource;
 import android.os.connectivity.WifiActivityEnergyInfo;
 import android.text.TextUtils;
+import android.util.CloseGuard;
 import android.util.Log;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
-import dalvik.system.CloseGuard;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -2156,8 +2156,6 @@
     /** @hide */
     public static final long WIFI_FEATURE_INFRA            = 0x0001L;  // Basic infrastructure mode
     /** @hide */
-    public static final long WIFI_FEATURE_INFRA_5G         = 0x0002L;  // Support for 5 GHz Band
-    /** @hide */
     public static final long WIFI_FEATURE_PASSPOINT        = 0x0004L;  // Support for GAS/ANQP
     /** @hide */
     public static final long WIFI_FEATURE_P2P              = 0x0008L;  // Wifi-Direct
@@ -2227,8 +2225,6 @@
     public static final long WIFI_FEATURE_MBO              = 0x800000000L; // MBO Support
     /** @hide */
     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
-    /** @hide */
-    public static final long WIFI_FEATURE_INFRA_6G         = 0x2000000000L; // Support 6 GHz band
 
     private long getSupportedFeatures() {
         try {
@@ -2242,22 +2238,7 @@
         return (getSupportedFeatures() & feature) == feature;
     }
 
-    /**
-     * @return true if this adapter supports 5 GHz band
-     */
-    public boolean is5GHzBandSupported() {
-        return isFeatureSupported(WIFI_FEATURE_INFRA_5G);
-    }
-
-    /**
-     * @return true if the device supports operating in the 6 GHz band and Wi-Fi is enabled,
-     *         false otherwise.
-     */
-    public boolean is6GHzBandSupported() {
-        return isFeatureSupported(WIFI_FEATURE_INFRA_6G);
-    }
-
-    /**
+   /**
      * @return true if this adapter supports Passpoint
      * @hide
      */
@@ -2379,6 +2360,30 @@
     }
 
     /**
+     * Check if the chipset supports 5GHz band.
+     * @return {@code true} if supported, {@code false} otherwise.
+     */
+    public boolean is5GHzBandSupported() {
+        try {
+            return mService.is5GHzBandSupported();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Check if the chipset supports 6GHz band.
+     * @return {@code true} if supported, {@code false} otherwise.
+     */
+    public boolean is6GHzBandSupported() {
+        try {
+            return mService.is6GHzBandSupported();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
      *
@@ -2592,21 +2597,6 @@
     }
 
     /**
-     * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz).
-     * No permissions are required to call this method.
-     * @return {@code true} if supported, {@code false} otherwise.
-     * @hide
-     */
-    @SystemApi
-    public boolean isDualBandSupported() {
-        try {
-            return mService.isDualBandSupported();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Check if the device is dual mode capable i.e. supports concurrent STA + Soft AP.
      *
      * If the device is dual mode capable, it may require conversion of the user's Soft AP band
@@ -3574,7 +3564,7 @@
      */
     public class LocalOnlyHotspotReservation implements AutoCloseable {
 
-        private final CloseGuard mCloseGuard = CloseGuard.get();
+        private final CloseGuard mCloseGuard = new CloseGuard();
         private final WifiConfiguration mConfig;
         private boolean mClosed = false;
 
@@ -3601,6 +3591,8 @@
                 }
             } catch (Exception e) {
                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
+            } finally {
+                Reference.reachabilityFence(this);
             }
         }
 
@@ -3725,7 +3717,7 @@
      * @hide
      */
     public class LocalOnlyHotspotSubscription implements AutoCloseable {
-        private final CloseGuard mCloseGuard = CloseGuard.get();
+        private final CloseGuard mCloseGuard = new CloseGuard();
 
         /** @hide */
         @VisibleForTesting
@@ -3740,6 +3732,8 @@
                 mCloseGuard.close();
             } catch (Exception e) {
                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
+            } finally {
+                Reference.reachabilityFence(this);
             }
         }
 
@@ -4686,10 +4680,13 @@
     }
 
     /**
-     * Retrieve the soft ap config data to be backed to save current config data.
+     * Returns a byte stream representing the data that needs to be backed up to save the
+     * current soft ap config data.
+     *
+     * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
      * @hide
      */
-    @Nullable
+    @NonNull
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public byte[] retrieveSoftApBackupData() {
@@ -4701,15 +4698,17 @@
     }
 
     /**
-     * Restore soft ap config from the backed up data.
+     * Returns soft ap config from the backed up data.
+     * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
+     *
      * @hide
      */
     @Nullable
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void restoreSoftApBackupData(@NonNull byte[] data) {
+    public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
         try {
-            mService.restoreSoftApBackupData(data);
+            return mService.restoreSoftApBackupData(data);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index d97f6fb..4d92ae1 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -20,12 +20,12 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.NetworkSpecifier;
+import android.util.CloseGuard;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
-import dalvik.system.CloseGuard;
-
+import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 
 /**
@@ -58,7 +58,7 @@
     /** @hide */
     protected boolean mTerminated = false;
 
-    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private final CloseGuard mCloseGuard = new CloseGuard();
 
     /**
      * Return the maximum permitted retry count when sending messages using
@@ -108,6 +108,7 @@
         mTerminated = true;
         mMgr.clear();
         mCloseGuard.close();
+        Reference.reachabilityFence(this);
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 3c97813..fe0872c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -23,12 +23,12 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.CloseGuard;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
-import dalvik.system.CloseGuard;
-
+import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 
 /**
@@ -45,7 +45,7 @@
     private final int mClientId;
 
     private boolean mTerminated = true;
-    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private final CloseGuard mCloseGuard = new CloseGuard();
 
     /** @hide */
     public WifiAwareSession(WifiAwareManager manager, Binder binder, int clientId) {
@@ -80,6 +80,7 @@
         mTerminated = true;
         mMgr.clear();
         mCloseGuard.close();
+        Reference.reachabilityFence(this);
     }
 
     /** @hide */
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 1c20679..6120e4e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -44,15 +44,15 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.CloseGuard;
 import android.util.Log;
 
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
-import dalvik.system.CloseGuard;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -869,7 +869,7 @@
         private final Object mListenerMapLock = new Object();
         private int mListenerKey = 0;
 
-        private final CloseGuard mCloseGuard = CloseGuard.get();
+        private final CloseGuard mCloseGuard = new CloseGuard();
 
         /**
          * Close the current P2P connection and indicate to the P2P service that connections
@@ -888,6 +888,7 @@
 
             mAsyncChannel.disconnect();
             mCloseGuard.close();
+            Reference.reachabilityFence(this);
         }
 
         /** @hide */
diff --git a/wifi/java/android/net/wifi/wificond/ChannelSettings.java b/wifi/java/android/net/wifi/wificond/ChannelSettings.java
new file mode 100644
index 0000000..c2d65b5
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/ChannelSettings.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * ChannelSettings for wificond
+ *
+ * @hide
+ */
+public class ChannelSettings implements Parcelable {
+    private static final String TAG = "ChannelSettings";
+
+    public int frequency;
+
+    /** public constructor */
+    public ChannelSettings() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof ChannelSettings)) {
+            return false;
+        }
+        ChannelSettings channel = (ChannelSettings) rhs;
+        if (channel == null) {
+            return false;
+        }
+        return frequency == channel.frequency;
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Objects.hash(frequency);
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flags| is ignored.
+     **/
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(frequency);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<ChannelSettings> CREATOR =
+            new Parcelable.Creator<ChannelSettings>() {
+        /**
+         * Caller is responsible for providing a valid parcel.
+         */
+        @Override
+        public ChannelSettings createFromParcel(Parcel in) {
+            ChannelSettings result = new ChannelSettings();
+            result.frequency = in.readInt();
+            if (in.dataAvail() != 0) {
+                Log.e(TAG, "Found trailing data after parcel parsing.");
+            }
+
+            return result;
+        }
+
+        @Override
+        public ChannelSettings[] newArray(int size) {
+            return new ChannelSettings[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/HiddenNetwork.java b/wifi/java/android/net/wifi/wificond/HiddenNetwork.java
new file mode 100644
index 0000000..38dacea
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/HiddenNetwork.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * HiddenNetwork for wificond
+ *
+ * @hide
+ */
+public class HiddenNetwork implements Parcelable {
+    private static final String TAG = "HiddenNetwork";
+
+    public byte[] ssid;
+
+    /** public constructor */
+    public HiddenNetwork() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof HiddenNetwork)) {
+            return false;
+        }
+        HiddenNetwork network = (HiddenNetwork) rhs;
+        return Arrays.equals(ssid, network.ssid);
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(ssid);
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flags| is ignored.
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(ssid);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<HiddenNetwork> CREATOR =
+            new Parcelable.Creator<HiddenNetwork>() {
+        /**
+         * Caller is responsible for providing a valid parcel.
+         */
+        @Override
+        public HiddenNetwork createFromParcel(Parcel in) {
+            HiddenNetwork result = new HiddenNetwork();
+            result.ssid = in.createByteArray();
+            return result;
+        }
+
+        @Override
+        public HiddenNetwork[] newArray(int size) {
+            return new HiddenNetwork[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/NativeScanResult.java b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
new file mode 100644
index 0000000..ff8e935
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * ScanResult from wificond
+ *
+ * @hide
+ */
+public class NativeScanResult implements Parcelable {
+    private static final int CAPABILITY_SIZE = 16;
+
+    public byte[] ssid;
+    public byte[] bssid;
+    public byte[] infoElement;
+    public int frequency;
+    public int signalMbm;
+    public long tsf;
+    public BitSet capability;
+    public boolean associated;
+    public List<RadioChainInfo> radioChainInfos;
+
+    /** public constructor */
+    public NativeScanResult() { }
+
+    /** copy constructor */
+    public NativeScanResult(NativeScanResult source) {
+        ssid = source.ssid.clone();
+        bssid = source.bssid.clone();
+        infoElement = source.infoElement.clone();
+        frequency = source.frequency;
+        signalMbm = source.signalMbm;
+        tsf = source.tsf;
+        capability = (BitSet) source.capability.clone();
+        associated = source.associated;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(ssid);
+        out.writeByteArray(bssid);
+        out.writeByteArray(infoElement);
+        out.writeInt(frequency);
+        out.writeInt(signalMbm);
+        out.writeLong(tsf);
+        int capabilityInt = 0;
+        for (int i = 0; i < CAPABILITY_SIZE; i++) {
+            if (capability.get(i)) {
+                capabilityInt |= 1 << i;
+            }
+        }
+        out.writeInt(capabilityInt);
+        out.writeInt(associated ? 1 : 0);
+        out.writeTypedList(radioChainInfos);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<NativeScanResult> CREATOR =
+            new Parcelable.Creator<NativeScanResult>() {
+        @Override
+        public NativeScanResult createFromParcel(Parcel in) {
+            NativeScanResult result = new NativeScanResult();
+            result.ssid = in.createByteArray();
+            result.bssid = in.createByteArray();
+            result.infoElement = in.createByteArray();
+            result.frequency = in.readInt();
+            result.signalMbm = in.readInt();
+            result.tsf = in.readLong();
+            int capabilityInt = in.readInt();
+            result.capability = new BitSet(CAPABILITY_SIZE);
+            for (int i = 0; i < CAPABILITY_SIZE; i++) {
+                if ((capabilityInt & (1 << i)) != 0) {
+                    result.capability.set(i);
+                }
+            }
+            result.associated = (in.readInt() != 0);
+            result.radioChainInfos = new ArrayList<>();
+            in.readTypedList(result.radioChainInfos, RadioChainInfo.CREATOR);
+            return result;
+        }
+
+        @Override
+        public NativeScanResult[] newArray(int size) {
+            return new NativeScanResult[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java
new file mode 100644
index 0000000..4994ebd
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * NativeWifiClient for wificond
+ *
+ * @hide
+ */
+public class NativeWifiClient implements Parcelable {
+    public byte[] macAddress;
+
+    /** public constructor */
+    public NativeWifiClient() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof NativeWifiClient)) {
+            return false;
+        }
+        NativeWifiClient other = (NativeWifiClient) rhs;
+        return Arrays.equals(macAddress, other.macAddress);
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(macAddress);
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flag| is ignored.
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(macAddress);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<NativeWifiClient> CREATOR =
+            new Parcelable.Creator<NativeWifiClient>() {
+                @Override
+                public NativeWifiClient createFromParcel(Parcel in) {
+                    NativeWifiClient result = new NativeWifiClient();
+                    result.macAddress = in.createByteArray();
+                    return result;
+                }
+
+                @Override
+                public NativeWifiClient[] newArray(int size) {
+                    return new NativeWifiClient[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/wificond/PnoNetwork.java b/wifi/java/android/net/wifi/wificond/PnoNetwork.java
new file mode 100644
index 0000000..f923fd3
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/PnoNetwork.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * PnoNetwork for wificond
+ *
+ * @hide
+ */
+public class PnoNetwork implements Parcelable {
+
+    public boolean isHidden;
+    public byte[] ssid;
+    public int[] frequencies;
+
+    /** public constructor */
+    public PnoNetwork() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof PnoNetwork)) {
+            return false;
+        }
+        PnoNetwork network = (PnoNetwork) rhs;
+        return Arrays.equals(ssid, network.ssid)
+                && Arrays.equals(frequencies, network.frequencies)
+                && isHidden == network.isHidden;
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                isHidden,
+                Arrays.hashCode(ssid),
+                Arrays.hashCode(frequencies));
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flag| is ignored.
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(isHidden ? 1 : 0);
+        out.writeByteArray(ssid);
+        out.writeIntArray(frequencies);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<PnoNetwork> CREATOR =
+            new Parcelable.Creator<PnoNetwork>() {
+        @Override
+        public PnoNetwork createFromParcel(Parcel in) {
+            PnoNetwork result = new PnoNetwork();
+            result.isHidden = in.readInt() != 0 ? true : false;
+            result.ssid = in.createByteArray();
+            result.frequencies = in.createIntArray();
+            return result;
+        }
+
+        @Override
+        public PnoNetwork[] newArray(int size) {
+            return new PnoNetwork[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/PnoSettings.java b/wifi/java/android/net/wifi/wificond/PnoSettings.java
new file mode 100644
index 0000000..96cf24f
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/PnoSettings.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * PnoSettings for wificond
+ *
+ * @hide
+ */
+public class PnoSettings implements Parcelable {
+    public int intervalMs;
+    public int min2gRssi;
+    public int min5gRssi;
+    public int min6gRssi;
+    public ArrayList<PnoNetwork> pnoNetworks;
+
+    /** public constructor */
+    public PnoSettings() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof PnoSettings)) {
+            return false;
+        }
+        PnoSettings settings = (PnoSettings) rhs;
+        if (settings == null) {
+            return false;
+        }
+        return intervalMs == settings.intervalMs
+                && min2gRssi == settings.min2gRssi
+                && min5gRssi == settings.min5gRssi
+                && min6gRssi == settings.min6gRssi
+                && pnoNetworks.equals(settings.pnoNetworks);
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Objects.hash(intervalMs, min2gRssi, min5gRssi, min6gRssi, pnoNetworks);
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flag| is ignored.
+     **/
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(intervalMs);
+        out.writeInt(min2gRssi);
+        out.writeInt(min5gRssi);
+        out.writeInt(min6gRssi);
+        out.writeTypedList(pnoNetworks);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<PnoSettings> CREATOR =
+            new Parcelable.Creator<PnoSettings>() {
+        @Override
+        public PnoSettings createFromParcel(Parcel in) {
+            PnoSettings result = new PnoSettings();
+            result.intervalMs = in.readInt();
+            result.min2gRssi = in.readInt();
+            result.min5gRssi = in.readInt();
+            result.min6gRssi = in.readInt();
+
+            result.pnoNetworks = new ArrayList<PnoNetwork>();
+            in.readTypedList(result.pnoNetworks, PnoNetwork.CREATOR);
+
+            return result;
+        }
+
+        @Override
+        public PnoSettings[] newArray(int size) {
+            return new PnoSettings[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java
new file mode 100644
index 0000000..2b03450
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * RadioChainInfo for wificond
+ *
+ * @hide
+ */
+public class RadioChainInfo implements Parcelable {
+    private static final String TAG = "RadioChainInfo";
+
+    public int chainId;
+    public int level;
+
+
+    /** public constructor */
+    public RadioChainInfo() { }
+
+    public RadioChainInfo(int chainId, int level) {
+        this.chainId = chainId;
+        this.level = level;
+    }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof RadioChainInfo)) {
+            return false;
+        }
+        RadioChainInfo chainInfo = (RadioChainInfo) rhs;
+        if (chainInfo == null) {
+            return false;
+        }
+        return chainId == chainInfo.chainId && level == chainInfo.level;
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Objects.hash(chainId, level);
+    }
+
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flags| is ignored.
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(chainId);
+        out.writeInt(level);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<RadioChainInfo> CREATOR =
+            new Parcelable.Creator<RadioChainInfo>() {
+        /**
+         * Caller is responsible for providing a valid parcel.
+         */
+        @Override
+        public RadioChainInfo createFromParcel(Parcel in) {
+            RadioChainInfo result = new RadioChainInfo();
+            result.chainId = in.readInt();
+            result.level = in.readInt();
+            return result;
+        }
+
+        @Override
+        public RadioChainInfo[] newArray(int size) {
+            return new RadioChainInfo[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/wificond/SingleScanSettings.java b/wifi/java/android/net/wifi/wificond/SingleScanSettings.java
new file mode 100644
index 0000000..8065c01
--- /dev/null
+++ b/wifi/java/android/net/wifi/wificond/SingleScanSettings.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import android.net.wifi.IWifiScannerImpl;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * SingleScanSettings for wificond
+ *
+ * @hide
+ */
+public class SingleScanSettings implements Parcelable {
+    private static final String TAG = "SingleScanSettings";
+
+    public int scanType;
+    public ArrayList<ChannelSettings> channelSettings;
+    public ArrayList<HiddenNetwork> hiddenNetworks;
+
+    /** public constructor */
+    public SingleScanSettings() { }
+
+    /** override comparator */
+    @Override
+    public boolean equals(Object rhs) {
+        if (this == rhs) return true;
+        if (!(rhs instanceof SingleScanSettings)) {
+            return false;
+        }
+        SingleScanSettings settings = (SingleScanSettings) rhs;
+        if (settings == null) {
+            return false;
+        }
+        return scanType == settings.scanType
+                && channelSettings.equals(settings.channelSettings)
+                && hiddenNetworks.equals(settings.hiddenNetworks);
+    }
+
+    /** override hash code */
+    @Override
+    public int hashCode() {
+        return Objects.hash(scanType, channelSettings, hiddenNetworks);
+    }
+
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private static boolean isValidScanType(int scanType) {
+        return scanType == IWifiScannerImpl.SCAN_TYPE_LOW_SPAN
+                || scanType == IWifiScannerImpl.SCAN_TYPE_LOW_POWER
+                || scanType == IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+    }
+
+    /**
+     * implement Parcelable interface
+     * |flags| is ignored.
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        if (!isValidScanType(scanType)) {
+            Log.wtf(TAG, "Invalid scan type " + scanType);
+        }
+        out.writeInt(scanType);
+        out.writeTypedList(channelSettings);
+        out.writeTypedList(hiddenNetworks);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<SingleScanSettings> CREATOR =
+            new Parcelable.Creator<SingleScanSettings>() {
+        /**
+         * Caller is responsible for providing a valid parcel.
+         */
+        @Override
+        public SingleScanSettings createFromParcel(Parcel in) {
+            SingleScanSettings result = new SingleScanSettings();
+            result.scanType = in.readInt();
+            if (!isValidScanType(result.scanType)) {
+                Log.wtf(TAG, "Invalid scan type " + result.scanType);
+            }
+            result.channelSettings = new ArrayList<ChannelSettings>();
+            in.readTypedList(result.channelSettings, ChannelSettings.CREATOR);
+            result.hiddenNetworks = new ArrayList<HiddenNetwork>();
+            in.readTypedList(result.hiddenNetworks, HiddenNetwork.CREATOR);
+            if (in.dataAvail() != 0) {
+                Log.e(TAG, "Found trailing data after parcel parsing.");
+            }
+            return result;
+        }
+
+        @Override
+        public SingleScanSettings[] newArray(int size) {
+            return new SingleScanSettings[size];
+        }
+    };
+}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 524a53c..d58083c 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -28,7 +28,6 @@
 import android.net.wifi.IOnWifiActivityEnergyInfoListener;
 import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.IScanResultsCallback;
-import android.net.wifi.IScanResultsListener;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ISuggestionConnectionStatusListener;
 import android.net.wifi.ITrafficStateCallback;
@@ -227,12 +226,23 @@
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated use {@link #is5GHzBandSupported} instead */
+    @Deprecated
     public boolean isDualBandSupported() {
         throw new UnsupportedOperationException();
     }
 
     @Override
+    public boolean is5GHzBandSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean is6GHzBandSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean needs5GHzToAnyApBandConversion() {
         throw new UnsupportedOperationException();
     }
@@ -414,7 +424,7 @@
     }
 
     @Override
-    public void restoreSoftApBackupData(byte[] data) {
+    public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java b/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java
new file mode 100644
index 0000000..48a9afa
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java
@@ -0,0 +1,1281 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.test.TestAlarmManager;
+import android.content.Context;
+import android.net.wifi.util.HexEncoding;
+import android.net.wifi.wificond.ChannelSettings;
+import android.net.wifi.wificond.HiddenNetwork;
+import android.net.wifi.wificond.NativeWifiClient;
+import android.net.wifi.wificond.PnoNetwork;
+import android.net.wifi.wificond.PnoSettings;
+import android.net.wifi.wificond.SingleScanSettings;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.AdditionalMatchers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiCondManager}.
+ */
+@SmallTest
+public class WifiCondManagerTest {
+    @Mock
+    private IWificond mWificond;
+    @Mock
+    private IBinder mWifiCondBinder;
+    @Mock
+    private IClientInterface mClientInterface;
+    @Mock
+    private IWifiScannerImpl mWifiScannerImpl;
+    @Mock
+    private IApInterface mApInterface;
+    @Mock
+    private WifiCondManager.SoftApListener mSoftApListener;
+    @Mock
+    private WifiCondManager.SendMgmtFrameCallback mSendMgmtFrameCallback;
+    @Mock
+    private WifiCondManager.ScanEventCallback mNormalScanCallback;
+    @Mock
+    private WifiCondManager.ScanEventCallback mPnoScanCallback;
+    @Mock
+    private WifiCondManager.PnoScanRequestCallback mPnoScanRequestCallback;
+    @Mock
+    private Context mContext;
+    private TestLooper mLooper;
+    private TestAlarmManager mTestAlarmManager;
+    private AlarmManager mAlarmManager;
+    private WifiCondManager mWificondControl;
+    private static final String TEST_INTERFACE_NAME = "test_wlan_if";
+    private static final String TEST_INTERFACE_NAME1 = "test_wlan_if1";
+    private static final String TEST_INVALID_INTERFACE_NAME = "asdf";
+    private static final byte[] TEST_SSID =
+            new byte[]{'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+    private static final byte[] TEST_PSK =
+            new byte[]{'T', 'e', 's', 't'};
+
+    private static final Set<Integer> SCAN_FREQ_SET =
+            new HashSet<Integer>() {{
+                add(2410);
+                add(2450);
+                add(5050);
+                add(5200);
+            }};
+    private static final String TEST_QUOTED_SSID_1 = "\"testSsid1\"";
+    private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
+    private static final int[] TEST_FREQUENCIES_1 = {};
+    private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+
+    private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST =
+            new ArrayList<byte[]>() {{
+                add(LocalNativeUtil.byteArrayFromArrayList(
+                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
+                add(LocalNativeUtil.byteArrayFromArrayList(
+                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
+            }};
+
+    private static final PnoSettings TEST_PNO_SETTINGS =
+            new PnoSettings() {{
+                intervalMs = 6000;
+                pnoNetworks = new ArrayList<>();
+                PnoNetwork network = new PnoNetwork();
+                network.ssid = LocalNativeUtil.byteArrayFromArrayList(
+                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1));
+                network.isHidden = true;
+                network.frequencies = TEST_FREQUENCIES_1;
+                pnoNetworks.add(network);
+                network.ssid = LocalNativeUtil.byteArrayFromArrayList(
+                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2));
+                network.isHidden = false;
+                network.frequencies = TEST_FREQUENCIES_2;
+                pnoNetworks.add(network);
+            }};
+
+    private static final int TEST_MCS_RATE = 5;
+    private static final int TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS = 100;
+    private static final byte[] TEST_PROBE_FRAME = {
+            0x40, 0x00, 0x3c, 0x00, (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b,
+            0x33, 0x72, (byte) 0xf4, (byte) 0xf5, (byte) 0xe8, 0x51, (byte) 0x9e, 0x09,
+            (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b, 0x33, 0x72, (byte) 0xb0, 0x66,
+            0x00, 0x00
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        // Setup mocks for successful WificondControl operation. Failure case mocks should be
+        // created in specific tests
+        MockitoAnnotations.initMocks(this);
+
+        mTestAlarmManager = new TestAlarmManager();
+        mAlarmManager = mTestAlarmManager.getAlarmManager();
+        when(mContext.getSystemServiceName(AlarmManager.class)).thenReturn(Context.ALARM_SERVICE);
+        when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+
+        mLooper = new TestLooper();
+        when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+
+        when(mWificond.asBinder()).thenReturn(mWifiCondBinder);
+        when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+        when(mWificond.createClientInterface(any())).thenReturn(mClientInterface);
+        when(mWificond.createApInterface(any())).thenReturn(mApInterface);
+        when(mWificond.tearDownClientInterface(any())).thenReturn(true);
+        when(mWificond.tearDownApInterface(any())).thenReturn(true);
+        when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+        when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+        mWificondControl = new WifiCondManager(mContext, mWificond);
+        assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+                mNormalScanCallback, mPnoScanCallback));
+    }
+
+    /**
+     * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testSetupInterfaceForClientMode() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+        verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls subscribeScanEvents().
+     */
+    @Test
+    public void testSetupInterfaceForClientModeCallsScanEventSubscripiton() throws Exception {
+        verify(mWifiScannerImpl).subscribeScanEvents(any(IScanEvent.class));
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownClientInterface() throws Exception {
+        when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+
+        assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+        verify(mWifiScannerImpl).unsubscribeScanEvents();
+        verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+        verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownClientInterfaceOnInvalidIface() throws Exception {
+        when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME1)).thenReturn(true);
+
+        assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME1));
+        verify(mWifiScannerImpl, never()).unsubscribeScanEvents();
+        verify(mWifiScannerImpl, never()).unsubscribePnoScanEvents();
+        verify(mWificond, never()).tearDownClientInterface(any());
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownClientInterfaceFailDueToExceptionScannerUnsubscribe() throws Exception {
+        when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+        doThrow(new RemoteException()).when(mWifiScannerImpl).unsubscribeScanEvents();
+
+        assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+        verify(mWifiScannerImpl).unsubscribeScanEvents();
+        verify(mWifiScannerImpl, never()).unsubscribePnoScanEvents();
+        verify(mWificond, never()).tearDownClientInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownClientInterfaceErrorWhenWificondFailed() throws Exception {
+        when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(false);
+
+        assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+        verify(mWifiScannerImpl).unsubscribeScanEvents();
+        verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+        verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that the client handles are cleared after teardown.
+     */
+    @Test
+    public void testTeardownClientInterfaceClearsHandles() throws Exception {
+        testTeardownClientInterface();
+
+        assertNull(mWificondControl.signalPoll(TEST_INTERFACE_NAME));
+        verify(mClientInterface, never()).signalPoll();
+
+        assertFalse(mWificondControl.scan(
+                TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+        verify(mWifiScannerImpl, never()).scan(any());
+    }
+
+    /**
+     * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) calls wificond.
+     */
+    @Test
+    public void testSetupInterfaceForSoftApMode() throws Exception {
+        when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(mApInterface);
+
+        assertEquals(true, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+        verify(mWificond).createApInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that setupInterfaceForSoftAp() returns null when wificond is not started.
+     */
+    @Test
+    public void testSetupInterfaceForSoftApModeErrorWhenWificondIsNotStarted() throws Exception {
+        // Invoke wificond death handler to clear the handle.
+        mWificondControl.binderDied();
+        mLooper.dispatchAll();
+
+        assertEquals(false, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+    }
+
+    /**
+     * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) returns null when wificond
+     * failed to setup AP interface.
+     */
+    @Test
+    public void testSetupInterfaceForSoftApModeErrorWhenWificondFailedToSetupInterface()
+            throws Exception {
+        when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(null);
+
+        assertEquals(false, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME));
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownSoftApInterface() throws Exception {
+        testSetupInterfaceForSoftApMode();
+        when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+
+        assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+        verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that tearDownSoftapInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownSoftApInterfaceOnInvalidIface() throws Exception {
+        testSetupInterfaceForSoftApMode();
+        when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME1)).thenReturn(true);
+
+        assertFalse(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME1));
+        verify(mWificond, never()).tearDownApInterface(any());
+    }
+
+    /**
+     * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+     */
+    @Test
+    public void testTeardownSoftApInterfaceErrorWhenWificondFailed() throws Exception {
+        testSetupInterfaceForSoftApMode();
+        when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(false);
+
+        assertFalse(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+        verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+    }
+
+    /**
+     * Verifies that the SoftAp handles are cleared after teardown.
+     */
+    @Test
+    public void testTeardownSoftApInterfaceClearsHandles() throws Exception {
+        testTeardownSoftApInterface();
+
+        assertFalse(mWificondControl.registerApListener(
+                TEST_INTERFACE_NAME, mSoftApListener));
+        verify(mApInterface, never()).registerCallback(any());
+    }
+
+    /**
+     * Verifies that we can setup concurrent interfaces.
+     */
+    @Test
+    public void testSetupMultipleInterfaces() throws Exception {
+        when(mWificond.createApInterface(TEST_INTERFACE_NAME1)).thenReturn(mApInterface);
+
+        assertEquals(true, mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME1));
+
+        verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
+        verify(mWificond).createApInterface(TEST_INTERFACE_NAME1);
+    }
+
+    /**
+     * Verifies that we can setup concurrent interfaces.
+     */
+    @Test
+    public void testTeardownMultipleInterfaces() throws Exception {
+        testSetupMultipleInterfaces();
+        assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+        assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME1));
+
+        verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+        verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME1);
+    }
+
+    /**
+     * Verifies that tearDownInterfaces() calls wificond.
+     */
+    @Test
+    public void testTearDownInterfaces() throws Exception {
+        assertTrue(mWificondControl.tearDownInterfaces());
+        verify(mWificond).tearDownInterfaces();
+    }
+
+    /**
+     * Verifies that tearDownInterfaces() calls unsubscribeScanEvents() when there was
+     * a configured client interface.
+     */
+    @Test
+    public void testTearDownInterfacesRemovesScanEventSubscription() throws Exception {
+        assertTrue(mWificondControl.tearDownInterfaces());
+        verify(mWifiScannerImpl).unsubscribeScanEvents();
+    }
+
+
+    /**
+     * Verifies that tearDownInterfaces() returns false when wificond is not started.
+     */
+    @Test
+    public void testTearDownInterfacesErrorWhenWificondIsNotStarterd() throws Exception {
+        // Invoke wificond death handler to clear the handle.
+        mWificondControl.binderDied();
+        mLooper.dispatchAll();
+        assertFalse(mWificondControl.tearDownInterfaces());
+    }
+
+    /**
+     * Verifies that signalPoll() calls wificond.
+     */
+    @Test
+    public void testSignalPoll() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
+                mPnoScanCallback);
+        mWificondControl.signalPoll(TEST_INTERFACE_NAME);
+        verify(mClientInterface).signalPoll();
+    }
+
+    /**
+     * Verifies that signalPoll() returns null when there is no configured client interface.
+     */
+    @Test
+    public void testSignalPollErrorWhenNoClientInterfaceConfigured() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+        // Configure client interface.
+        assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+                mNormalScanCallback, mPnoScanCallback));
+
+        // Tear down interfaces.
+        assertTrue(mWificondControl.tearDownInterfaces());
+
+        // Signal poll should fail.
+        assertEquals(null, mWificondControl.signalPoll(TEST_INTERFACE_NAME));
+    }
+
+    /**
+     * Verifies that getTxPacketCounters() calls wificond.
+     */
+    @Test
+    public void testGetTxPacketCounters() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
+                mPnoScanCallback);
+        mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME);
+        verify(mClientInterface).getPacketCounters();
+    }
+
+    /**
+     * Verifies that getTxPacketCounters() returns null when there is no configured client
+     * interface.
+     */
+    @Test
+    public void testGetTxPacketCountersErrorWhenNoClientInterfaceConfigured() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+        // Configure client interface.
+        assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+                mNormalScanCallback, mPnoScanCallback));
+
+        // Tear down interfaces.
+        assertTrue(mWificondControl.tearDownInterfaces());
+
+        // Signal poll should fail.
+        assertEquals(null, mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME));
+    }
+
+    /**
+     * Verifies that getScanResults() returns null when there is no configured client
+     * interface.
+     */
+    @Test
+    public void testGetScanResultsErrorWhenNoClientInterfaceConfigured() throws Exception {
+        when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+
+        // Configure client interface.
+        assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
+                mNormalScanCallback, mPnoScanCallback));
+
+        // Tear down interfaces.
+        assertTrue(mWificondControl.tearDownInterfaces());
+
+        // getScanResults should fail.
+        assertEquals(0,
+                mWificondControl.getScanResults(TEST_INTERFACE_NAME,
+                        WifiCondManager.SCAN_TYPE_SINGLE_SCAN).size());
+    }
+
+    /**
+     * Verifies that Scan() can convert input parameters to SingleScanSettings correctly.
+     */
+    @Test
+    public void testScan() throws Exception {
+        when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+        assertTrue(mWificondControl.scan(
+                TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+        verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+                IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+    }
+
+    /**
+     * Verifies that Scan() removes duplicates hiddenSsids passed in from input.
+     */
+    @Test
+    public void testScanWithDuplicateHiddenSsids() throws Exception {
+        when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+        // Create a list of hiddenSsid that has a duplicate element
+        List<byte[]> hiddenSsidWithDup = new ArrayList<>(SCAN_HIDDEN_NETWORK_SSID_LIST);
+        hiddenSsidWithDup.add(SCAN_HIDDEN_NETWORK_SSID_LIST.get(0));
+        assertEquals(hiddenSsidWithDup.get(0),
+                hiddenSsidWithDup.get(hiddenSsidWithDup.size() - 1));
+        // Pass the List with duplicate elements into scan()
+        assertTrue(mWificondControl.scan(
+                TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
+                SCAN_FREQ_SET, hiddenSsidWithDup));
+        // But the argument passed down should have the duplicate removed.
+        verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+                IWifiScannerImpl.SCAN_TYPE_LOW_POWER,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST)));
+    }
+
+    /**
+     * Verifies that Scan() can handle null input parameters correctly.
+     */
+    @Test
+    public void testScanNullParameters() throws Exception {
+        when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+        assertTrue(mWificondControl.scan(
+                TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
+        verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
+                IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null)));
+    }
+
+    /**
+     * Verifies that Scan() can handle wificond scan failure.
+     */
+    @Test
+    public void testScanFailure() throws Exception {
+        when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(false);
+        assertFalse(mWificondControl.scan(
+                TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+        verify(mWifiScannerImpl).scan(any(SingleScanSettings.class));
+    }
+
+    /**
+     * Verifies that Scan() can handle invalid type.
+     */
+    @Test
+    public void testScanFailureDueToInvalidType() throws Exception {
+        assertFalse(mWificondControl.scan(
+                TEST_INTERFACE_NAME, 100,
+                SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
+        verify(mWifiScannerImpl, never()).scan(any(SingleScanSettings.class));
+    }
+
+    /**
+     * Verifies that startPnoScan() can convert input parameters to PnoSettings correctly.
+     */
+    @Test
+    public void testStartPnoScan() throws Exception {
+        when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(true);
+        assertTrue(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
+                mPnoScanRequestCallback));
+        verify(mWifiScannerImpl).startPnoScan(argThat(new PnoScanMatcher(TEST_PNO_SETTINGS)));
+        verify(mPnoScanRequestCallback).onPnoRequestSucceeded();
+    }
+
+    /**
+     * Verifies that stopPnoScan() calls underlying wificond.
+     */
+    @Test
+    public void testStopPnoScan() throws Exception {
+        when(mWifiScannerImpl.stopPnoScan()).thenReturn(true);
+        assertTrue(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+        verify(mWifiScannerImpl).stopPnoScan();
+    }
+
+    /**
+     * Verifies that stopPnoScan() can handle wificond failure.
+     */
+    @Test
+    public void testStopPnoScanFailure() throws Exception {
+
+        when(mWifiScannerImpl.stopPnoScan()).thenReturn(false);
+        assertFalse(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+        verify(mWifiScannerImpl).stopPnoScan();
+    }
+
+    /**
+     * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon scan
+     * result event.
+     */
+    @Test
+    public void testScanResultEvent() throws Exception {
+        ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
+        verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
+        IScanEvent scanEvent = messageCaptor.getValue();
+        assertNotNull(scanEvent);
+        scanEvent.OnScanResultReady();
+
+        verify(mNormalScanCallback).onScanResultReady();
+    }
+
+    /**
+     * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon scan
+     * failed event.
+     */
+    @Test
+    public void testScanFailedEvent() throws Exception {
+        ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
+        verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
+        IScanEvent scanEvent = messageCaptor.getValue();
+        assertNotNull(scanEvent);
+        scanEvent.OnScanFailed();
+
+        verify(mNormalScanCallback).onScanFailed();
+    }
+
+    /**
+     * Verifies that WificondControl can invoke WifiMonitor broadcast methods upon pno scan
+     * result event.
+     */
+    @Test
+    public void testPnoScanResultEvent() throws Exception {
+        ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
+        verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
+        IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
+        assertNotNull(pnoScanEvent);
+        pnoScanEvent.OnPnoNetworkFound();
+        verify(mPnoScanCallback).onScanResultReady();
+    }
+
+    /**
+     * Verifies that WificondControl can invoke WifiMetrics pno scan count methods upon pno event.
+     */
+    @Test
+    public void testPnoScanEventsForMetrics() throws Exception {
+        ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
+        verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
+        IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
+        assertNotNull(pnoScanEvent);
+
+        pnoScanEvent.OnPnoNetworkFound();
+        verify(mPnoScanCallback).onScanResultReady();
+
+        pnoScanEvent.OnPnoScanFailed();
+        verify(mPnoScanCallback).onScanFailed();
+    }
+
+    /**
+     * Verifies that startPnoScan() can invoke WifiMetrics pno scan count methods correctly.
+     */
+    @Test
+    public void testStartPnoScanForMetrics() throws Exception {
+        when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(false);
+
+        assertFalse(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
+                mPnoScanRequestCallback));
+        verify(mPnoScanRequestCallback).onPnoRequestFailed();
+    }
+
+    /**
+     * Verifies that abortScan() calls underlying wificond.
+     */
+    @Test
+    public void testAbortScan() throws Exception {
+        mWificondControl.abortScan(TEST_INTERFACE_NAME);
+        verify(mWifiScannerImpl).abortScan();
+    }
+
+    /**
+     * Ensures that the Ap interface callbacks are forwarded to the
+     * SoftApListener used for starting soft AP.
+     */
+    @Test
+    public void testSoftApListenerInvocation() throws Exception {
+        testSetupInterfaceForSoftApMode();
+
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+        when(mApInterface.registerCallback(any())).thenReturn(true);
+
+        final ArgumentCaptor<IApInterfaceEventCallback> apInterfaceCallbackCaptor =
+                ArgumentCaptor.forClass(IApInterfaceEventCallback.class);
+
+        assertTrue(mWificondControl.registerApListener(
+                TEST_INTERFACE_NAME, mSoftApListener));
+        verify(mApInterface).registerCallback(apInterfaceCallbackCaptor.capture());
+
+        final NativeWifiClient testClient = new NativeWifiClient();
+        apInterfaceCallbackCaptor.getValue().onConnectedClientsChanged(testClient, true);
+        verify(mSoftApListener).onConnectedClientsChanged(eq(testClient), eq(true));
+
+        int channelFrequency = 2437;
+        int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20;
+        apInterfaceCallbackCaptor.getValue().onSoftApChannelSwitched(channelFrequency,
+                channelBandwidth);
+        verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency), eq(channelBandwidth));
+    }
+
+    /**
+     * Verifies registration and invocation of wificond death handler.
+     */
+    @Test
+    public void testRegisterDeathHandler() throws Exception {
+        Runnable deathHandler = mock(Runnable.class);
+        assertTrue(mWificondControl.initialize(deathHandler));
+        verify(mWificond).tearDownInterfaces();
+        mWificondControl.binderDied();
+        mLooper.dispatchAll();
+        verify(deathHandler).run();
+    }
+
+    /**
+     * Verifies handling of wificond death and ensures that all internal state is cleared and
+     * handlers are invoked.
+     */
+    @Test
+    public void testDeathHandling() throws Exception {
+        Runnable deathHandler = mock(Runnable.class);
+        assertTrue(mWificondControl.initialize(deathHandler));
+
+        testSetupInterfaceForClientMode();
+
+        mWificondControl.binderDied();
+        mLooper.dispatchAll();
+        verify(deathHandler).run();
+
+        // The handles should be cleared after death.
+        assertNull(mWificondControl.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
+        verify(mWificond, never()).getAvailable5gNonDFSChannels();
+    }
+
+    /**
+     * sendMgmtFrame() should fail if a null callback is passed in.
+     */
+    @Test
+    public void testSendMgmtFrameNullCallback() throws Exception {
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, null, TEST_MCS_RATE);
+
+        verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+    }
+
+    /**
+     * sendMgmtFrame() should fail if a null frame is passed in.
+     */
+    @Test
+    public void testSendMgmtFrameNullFrame() throws Exception {
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null,
+                mSendMgmtFrameCallback, TEST_MCS_RATE);
+
+        verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+        verify(mSendMgmtFrameCallback).onFailure(anyInt());
+    }
+
+    /**
+     * sendMgmtFrame() should fail if an interface name that does not exist is passed in.
+     */
+    @Test
+    public void testSendMgmtFrameInvalidInterfaceName() throws Exception {
+        mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME,
+                mSendMgmtFrameCallback, TEST_MCS_RATE);
+
+        verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
+        verify(mSendMgmtFrameCallback).onFailure(anyInt());
+    }
+
+    /**
+     * sendMgmtFrame() should fail if it is called a second time before the first call completed.
+     */
+    @Test
+    public void testSendMgmtFrameCalledTwiceBeforeFinished() throws Exception {
+        WifiCondManager.SendMgmtFrameCallback cb1 = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+        WifiCondManager.SendMgmtFrameCallback cb2 = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb1, TEST_MCS_RATE);
+        verify(cb1, never()).onFailure(anyInt());
+        verify(mClientInterface, times(1))
+                .SendMgmtFrame(AdditionalMatchers.aryEq(TEST_PROBE_FRAME),
+                        any(), eq(TEST_MCS_RATE));
+
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb2, TEST_MCS_RATE);
+        verify(cb2).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
+        // verify SendMgmtFrame() still was only called once i.e. not called again
+        verify(mClientInterface, times(1))
+                .SendMgmtFrame(any(), any(), anyInt());
+    }
+
+    /**
+     * Tests that when a RemoteException is triggered on AIDL call, onFailure() is called only once.
+     */
+    @Test
+    public void testSendMgmtFrameThrowsException() throws Exception {
+        WifiCondManager.SendMgmtFrameCallback cb = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+
+        doThrow(new RemoteException()).when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
+                cb, TEST_MCS_RATE);
+        mLooper.dispatchAll();
+
+        verify(cb).onFailure(anyInt());
+        verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+        sendMgmtFrameEventCaptor.getValue().OnFailure(
+                WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+        mLooper.dispatchAll();
+
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        mLooper.dispatchAll();
+
+        verifyNoMoreInteractions(cb);
+    }
+
+    /**
+     * Tests that the onAck() callback is triggered correctly.
+     */
+    @Test
+    public void testSendMgmtFrameSuccess() throws Exception {
+        WifiCondManager.SendMgmtFrameCallback cb = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+        doNothing().when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+
+        sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+        mLooper.dispatchAll();
+        verify(cb).onAck(eq(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS));
+        verify(cb, never()).onFailure(anyInt());
+        verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+        // verify that even if timeout is triggered afterwards, SendMgmtFrameCallback is not
+        // triggered again
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        mLooper.dispatchAll();
+        verify(cb, times(1)).onAck(anyInt());
+        verify(cb, never()).onFailure(anyInt());
+    }
+
+    /**
+     * Tests that the onFailure() callback is triggered correctly.
+     */
+    @Test
+    public void testSendMgmtFrameFailure() throws Exception {
+        WifiCondManager.SendMgmtFrameCallback cb = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+        doNothing().when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+
+        sendMgmtFrameEventCaptor.getValue().OnFailure(
+                WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+        mLooper.dispatchAll();
+        verify(cb, never()).onAck(anyInt());
+        verify(cb).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+        verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue()));
+
+        // verify that even if timeout is triggered afterwards, SendMgmtFrameCallback is not
+        // triggered again
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        mLooper.dispatchAll();
+        verify(cb, never()).onAck(anyInt());
+        verify(cb, times(1)).onFailure(anyInt());
+    }
+
+    /**
+     * Tests that the onTimeout() callback is triggered correctly.
+     */
+    @Test
+    public void testSendMgmtFrameTimeout() throws Exception {
+        WifiCondManager.SendMgmtFrameCallback cb = mock(
+                WifiCondManager.SendMgmtFrameCallback.class);
+
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+        doNothing().when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        mLooper.dispatchAll();
+        verify(cb, never()).onAck(anyInt());
+        verify(cb).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+
+        // verify that even if onAck() callback is triggered after timeout,
+        // SendMgmtFrameCallback is not triggered again
+        sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+        mLooper.dispatchAll();
+        verify(cb, never()).onAck(anyInt());
+        verify(cb, times(1)).onFailure(anyInt());
+    }
+
+    /**
+     * Tests every possible test outcome followed by every other test outcome to ensure that the
+     * internal state is reset correctly between calls.
+     * i.e. (success, success), (success, failure), (success, timeout),
+     * (failure, failure), (failure, success), (failure, timeout),
+     * (timeout, timeout), (timeout, success), (timeout, failure)
+     *
+     * Also tests that internal state is reset correctly after a transient AIDL RemoteException.
+     */
+    @Test
+    public void testSendMgmtFrameMixed() throws Exception {
+        testSendMgmtFrameThrowsException();
+        testSendMgmtFrameSuccess();
+        testSendMgmtFrameSuccess();
+        testSendMgmtFrameFailure();
+        testSendMgmtFrameFailure();
+        testSendMgmtFrameTimeout();
+        testSendMgmtFrameTimeout();
+        testSendMgmtFrameSuccess();
+        testSendMgmtFrameTimeout();
+        testSendMgmtFrameFailure();
+        testSendMgmtFrameSuccess();
+    }
+
+    /**
+     * Tests that OnAck() does not perform any non-thread-safe operations on the binder thread.
+     *
+     * The sequence of instructions are:
+     * 1. post onAlarm() onto main thread
+     * 2. OnAck()
+     * 3. mLooper.dispatchAll()
+     *
+     * The actual order of execution is:
+     * 1. binder thread portion of OnAck()
+     * 2. onAlarm() (which purely executes on the main thread)
+     * 3. main thread portion of OnAck()
+     *
+     * If the binder thread portion of OnAck() is not thread-safe, it can possibly mess up
+     * onAlarm(). Tests that this does not occur.
+     */
+    @Test
+    public void testSendMgmtFrameTimeoutAckThreadSafe() throws Exception {
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+        doNothing().when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
+                mSendMgmtFrameCallback, TEST_MCS_RATE);
+
+        // AlarmManager should post the onAlarm() callback onto the handler, but since we are
+        // triggering onAlarm() ourselves during the test, manually post onto handler
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        // OnAck posts to the handler
+        sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
+        mLooper.dispatchAll();
+        verify(mSendMgmtFrameCallback, never()).onAck(anyInt());
+        verify(mSendMgmtFrameCallback).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+    }
+
+    /**
+     * See {@link #testSendMgmtFrameTimeoutAckThreadSafe()}. This test replaces OnAck() with
+     * OnFailure().
+     */
+    @Test
+    public void testSendMgmtFrameTimeoutFailureThreadSafe() throws Exception {
+        final ArgumentCaptor<ISendMgmtFrameEvent> sendMgmtFrameEventCaptor =
+                ArgumentCaptor.forClass(ISendMgmtFrameEvent.class);
+        doNothing().when(mClientInterface)
+                .SendMgmtFrame(any(), sendMgmtFrameEventCaptor.capture(), anyInt());
+        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+        final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
+                alarmListenerCaptor.capture(), handlerCaptor.capture());
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
+                mSendMgmtFrameCallback, TEST_MCS_RATE);
+
+        // AlarmManager should post the onAlarm() callback onto the handler, but since we are
+        // triggering onAlarm() ourselves during the test, manually post onto handler
+        handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
+        // OnFailure posts to the handler
+        sendMgmtFrameEventCaptor.getValue().OnFailure(
+                WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
+        mLooper.dispatchAll();
+        verify(mSendMgmtFrameCallback).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_TIMEOUT);
+    }
+
+    // Create a ArgumentMatcher which captures a SingleScanSettings parameter and checks if it
+    // matches the provided frequency set and ssid set.
+    private class ScanMatcher implements ArgumentMatcher<SingleScanSettings> {
+        int mExpectedScanType;
+        private final Set<Integer> mExpectedFreqs;
+        private final List<byte[]> mExpectedSsids;
+
+        ScanMatcher(int expectedScanType, Set<Integer> expectedFreqs, List<byte[]> expectedSsids) {
+            this.mExpectedScanType = expectedScanType;
+            this.mExpectedFreqs = expectedFreqs;
+            this.mExpectedSsids = expectedSsids;
+        }
+
+        @Override
+        public boolean matches(SingleScanSettings settings) {
+            if (settings.scanType != mExpectedScanType) {
+                return false;
+            }
+            ArrayList<ChannelSettings> channelSettings = settings.channelSettings;
+            ArrayList<HiddenNetwork> hiddenNetworks = settings.hiddenNetworks;
+            if (mExpectedFreqs != null) {
+                Set<Integer> freqSet = new HashSet<Integer>();
+                for (ChannelSettings channel : channelSettings) {
+                    freqSet.add(channel.frequency);
+                }
+                if (!mExpectedFreqs.equals(freqSet)) {
+                    return false;
+                }
+            } else {
+                if (channelSettings != null && channelSettings.size() > 0) {
+                    return false;
+                }
+            }
+
+            if (mExpectedSsids != null) {
+                List<byte[]> ssidSet = new ArrayList<>();
+                for (HiddenNetwork network : hiddenNetworks) {
+                    ssidSet.add(network.ssid);
+                }
+                if (!mExpectedSsids.equals(ssidSet)) {
+                    return false;
+                }
+
+            } else {
+                if (hiddenNetworks != null && hiddenNetworks.size() > 0) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "ScanMatcher{mExpectedFreqs=" + mExpectedFreqs
+                    + ", mExpectedSsids=" + mExpectedSsids + '}';
+        }
+    }
+
+    // Create a ArgumentMatcher which captures a PnoSettings parameter and checks if it
+    // matches the WifiNative.PnoSettings;
+    private class PnoScanMatcher implements ArgumentMatcher<PnoSettings> {
+        private final PnoSettings mExpectedPnoSettings;
+
+        PnoScanMatcher(PnoSettings expectedPnoSettings) {
+            this.mExpectedPnoSettings = expectedPnoSettings;
+        }
+
+        @Override
+        public boolean matches(PnoSettings settings) {
+            if (mExpectedPnoSettings == null) {
+                return false;
+            }
+            if (settings.intervalMs != mExpectedPnoSettings.intervalMs
+                    || settings.min2gRssi != mExpectedPnoSettings.min2gRssi
+                    || settings.min5gRssi != mExpectedPnoSettings.min5gRssi
+                    || settings.min6gRssi != mExpectedPnoSettings.min6gRssi) {
+                return false;
+            }
+            if (settings.pnoNetworks == null || mExpectedPnoSettings.pnoNetworks == null) {
+                return false;
+            }
+            if (settings.pnoNetworks.size() != mExpectedPnoSettings.pnoNetworks.size()) {
+                return false;
+            }
+
+            for (int i = 0; i < settings.pnoNetworks.size(); i++) {
+                if (!Arrays.equals(settings.pnoNetworks.get(i).ssid,
+                        mExpectedPnoSettings.pnoNetworks.get(i).ssid)) {
+                    return false;
+                }
+                if (settings.pnoNetworks.get(i).isHidden != mExpectedPnoSettings.pnoNetworks.get(
+                        i).isHidden) {
+                    return false;
+                }
+                if (!Arrays.equals(settings.pnoNetworks.get(i).frequencies,
+                        mExpectedPnoSettings.pnoNetworks.get(i).frequencies)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "PnoScanMatcher{" + "mExpectedPnoSettings=" + mExpectedPnoSettings + '}';
+        }
+    }
+
+    private static class LocalNativeUtil {
+        private static final int SSID_BYTES_MAX_LEN = 32;
+
+        /**
+         * Converts an ArrayList<Byte> of UTF_8 byte values to string.
+         * The string will either be:
+         * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non
+         * null),
+         * or
+         * b) Hex string with no delimiters.
+         *
+         * @param bytes List of bytes for ssid.
+         * @throws IllegalArgumentException for null bytes.
+         */
+        public static String bytesToHexOrQuotedString(ArrayList<Byte> bytes) {
+            if (bytes == null) {
+                throw new IllegalArgumentException("null ssid bytes");
+            }
+            byte[] byteArray = byteArrayFromArrayList(bytes);
+            // Check for 0's in the byte stream in which case we cannot convert this into a string.
+            if (!bytes.contains(Byte.valueOf((byte) 0))) {
+                CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
+                try {
+                    CharBuffer decoded = decoder.decode(ByteBuffer.wrap(byteArray));
+                    return "\"" + decoded.toString() + "\"";
+                } catch (CharacterCodingException cce) {
+                }
+            }
+            return hexStringFromByteArray(byteArray);
+        }
+
+        /**
+         * Converts an ssid string to an arraylist of UTF_8 byte values.
+         * These forms are acceptable:
+         * a) UTF-8 String encapsulated in quotes, or
+         * b) Hex string with no delimiters.
+         *
+         * @param ssidStr String to be converted.
+         * @throws IllegalArgumentException for null string.
+         */
+        public static ArrayList<Byte> decodeSsid(String ssidStr) {
+            ArrayList<Byte> ssidBytes = hexOrQuotedStringToBytes(ssidStr);
+            if (ssidBytes.size() > SSID_BYTES_MAX_LEN) {
+                throw new IllegalArgumentException(
+                        "ssid bytes size out of range: " + ssidBytes.size());
+            }
+            return ssidBytes;
+        }
+
+        /**
+         * Convert from an array list of Byte to an array of primitive bytes.
+         */
+        public static byte[] byteArrayFromArrayList(ArrayList<Byte> bytes) {
+            byte[] byteArray = new byte[bytes.size()];
+            int i = 0;
+            for (Byte b : bytes) {
+                byteArray[i++] = b;
+            }
+            return byteArray;
+        }
+
+        /**
+         * Converts a byte array to hex string.
+         *
+         * @param bytes List of bytes for ssid.
+         * @throws IllegalArgumentException for null bytes.
+         */
+        public static String hexStringFromByteArray(byte[] bytes) {
+            if (bytes == null) {
+                throw new IllegalArgumentException("null hex bytes");
+            }
+            return new String(HexEncoding.encode(bytes)).toLowerCase();
+        }
+
+        /**
+         * Converts an string to an arraylist of UTF_8 byte values.
+         * These forms are acceptable:
+         * a) UTF-8 String encapsulated in quotes, or
+         * b) Hex string with no delimiters.
+         *
+         * @param str String to be converted.
+         * @throws IllegalArgumentException for null string.
+         */
+        public static ArrayList<Byte> hexOrQuotedStringToBytes(String str) {
+            if (str == null) {
+                throw new IllegalArgumentException("null string");
+            }
+            int length = str.length();
+            if ((length > 1) && (str.charAt(0) == '"') && (str.charAt(length - 1) == '"')) {
+                str = str.substring(1, str.length() - 1);
+                return stringToByteArrayList(str);
+            } else {
+                return byteArrayToArrayList(hexStringToByteArray(str));
+            }
+        }
+
+        /**
+         * Convert the string to byte array list.
+         *
+         * @return the UTF_8 char byte values of str, as an ArrayList.
+         * @throws IllegalArgumentException if a null or unencodable string is sent.
+         */
+        public static ArrayList<Byte> stringToByteArrayList(String str) {
+            if (str == null) {
+                throw new IllegalArgumentException("null string");
+            }
+            // Ensure that the provided string is UTF_8 encoded.
+            CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
+            try {
+                ByteBuffer encoded = encoder.encode(CharBuffer.wrap(str));
+                byte[] byteArray = new byte[encoded.remaining()];
+                encoded.get(byteArray);
+                return byteArrayToArrayList(byteArray);
+            } catch (CharacterCodingException cce) {
+                throw new IllegalArgumentException("cannot be utf-8 encoded", cce);
+            }
+        }
+
+        /**
+         * Convert from an array of primitive bytes to an array list of Byte.
+         */
+        public static ArrayList<Byte> byteArrayToArrayList(byte[] bytes) {
+            ArrayList<Byte> byteList = new ArrayList<>();
+            for (Byte b : bytes) {
+                byteList.add(b);
+            }
+            return byteList;
+        }
+
+        /**
+         * Converts a hex string to byte array.
+         *
+         * @param hexStr String to be converted.
+         * @throws IllegalArgumentException for null string.
+         */
+        public static byte[] hexStringToByteArray(String hexStr) {
+            if (hexStr == null) {
+                throw new IllegalArgumentException("null hex string");
+            }
+            return HexEncoding.decode(hexStr.toCharArray(), false);
+        }
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f92d38c..62ff9f65 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1696,8 +1696,6 @@
         assertTrue(mWifiManager.isPasspointSupported());
         assertTrue(mWifiManager.isP2pSupported());
         assertFalse(mWifiManager.isPortableHotspotSupported());
-        assertFalse(mWifiManager.is5GHzBandSupported());
-        assertFalse(mWifiManager.is6GHzBandSupported());
         assertFalse(mWifiManager.isDeviceToDeviceRttSupported());
         assertFalse(mWifiManager.isDeviceToApRttSupported());
         assertFalse(mWifiManager.isPreferredNetworkOffloadSupported());
@@ -1782,13 +1780,23 @@
     }
 
     /**
-     * Test behavior of {@link WifiManager#isDualBandSupported()}
+     * Test behavior of {@link WifiManager#is5GHzBandSupported()}
      */
     @Test
-    public void testIsDualBandSupported() throws Exception {
-        when(mWifiService.isDualBandSupported()).thenReturn(true);
-        assertTrue(mWifiManager.isDualBandSupported());
-        verify(mWifiService).isDualBandSupported();
+    public void testIs5GHzBandSupported() throws Exception {
+        when(mWifiService.is5GHzBandSupported()).thenReturn(true);
+        assertTrue(mWifiManager.is5GHzBandSupported());
+        verify(mWifiService).is5GHzBandSupported();
+    }
+
+    /**
+     * Test behavior of {@link WifiManager#is6GHzBandSupported()}
+     */
+    @Test
+    public void testIs6GHzBandSupported() throws Exception {
+        when(mWifiService.is6GHzBandSupported()).thenReturn(true);
+        assertTrue(mWifiManager.is6GHzBandSupported());
+        verify(mWifiService).is6GHzBandSupported();
     }
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java b/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
new file mode 100644
index 0000000..06f12f7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+
+/**
+ * Unit tests for {@link android.net.wifi.wificond.NativeScanResult}.
+ */
+@SmallTest
+public class NativeScanResultTest {
+
+    private static final byte[] TEST_SSID =
+            new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+    private static final byte[] TEST_BSSID =
+            new byte[] {(byte) 0x12, (byte) 0xef, (byte) 0xa1,
+                        (byte) 0x2c, (byte) 0x97, (byte) 0x8b};
+    private static final byte[] TEST_INFO_ELEMENT =
+            new byte[] {(byte) 0x01, (byte) 0x03, (byte) 0x12, (byte) 0xbe, (byte) 0xff};
+    private static final int TEST_FREQUENCY = 2456;
+    private static final int TEST_SIGNAL_MBM = -45;
+    private static final long TEST_TSF = 34455441;
+    private static final BitSet TEST_CAPABILITY = new BitSet(16) {{ set(2); set(5); }};
+    private static final boolean TEST_ASSOCIATED = true;
+    private static final int[] RADIO_CHAIN_IDS = { 0, 1 };
+    private static final int[] RADIO_CHAIN_LEVELS = { -56, -65 };
+
+    /**
+     *  NativeScanResult object can be serialized and deserialized, while keeping the
+     *  values unchanged.
+     */
+    @Test
+    public void canSerializeAndDeserialize() {
+        NativeScanResult scanResult = new NativeScanResult();
+        scanResult.ssid = TEST_SSID;
+        scanResult.bssid = TEST_BSSID;
+        scanResult.infoElement = TEST_INFO_ELEMENT;
+        scanResult.frequency = TEST_FREQUENCY;
+        scanResult.signalMbm = TEST_SIGNAL_MBM;
+        scanResult.tsf = TEST_TSF;
+        scanResult.capability = TEST_CAPABILITY;
+        scanResult.associated = TEST_ASSOCIATED;
+        scanResult.radioChainInfos = new ArrayList<>(Arrays.asList(
+                new RadioChainInfo(RADIO_CHAIN_IDS[0], RADIO_CHAIN_LEVELS[0]),
+                new RadioChainInfo(RADIO_CHAIN_IDS[1], RADIO_CHAIN_LEVELS[1])));
+        Parcel parcel = Parcel.obtain();
+        scanResult.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        NativeScanResult scanResultDeserialized = NativeScanResult.CREATOR.createFromParcel(parcel);
+
+        assertArrayEquals(scanResult.ssid, scanResultDeserialized.ssid);
+        assertArrayEquals(scanResult.bssid, scanResultDeserialized.bssid);
+        assertArrayEquals(scanResult.infoElement, scanResultDeserialized.infoElement);
+        assertEquals(scanResult.frequency, scanResultDeserialized.frequency);
+        assertEquals(scanResult.signalMbm, scanResultDeserialized.signalMbm);
+        assertEquals(scanResult.tsf, scanResultDeserialized.tsf);
+        assertEquals(scanResult.capability, scanResultDeserialized.capability);
+        assertEquals(scanResult.associated, scanResultDeserialized.associated);
+        assertTrue(scanResult.radioChainInfos.containsAll(scanResultDeserialized.radioChainInfos));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
new file mode 100644
index 0000000..775acc7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * Unit tests for {@link android.net.wifi.wificond.PnoSettingsResult}.
+ */
+@SmallTest
+public class PnoSettingsTest {
+
+    private static final byte[] TEST_SSID_1 =
+            new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+    private static final byte[] TEST_SSID_2 =
+            new byte[] {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'T', 'e', 's', 't'};
+    private static final int[] TEST_FREQUENCIES_1 = {};
+    private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+    private static final int TEST_INTERVAL_MS = 30000;
+    private static final int TEST_MIN_2G_RSSI = -60;
+    private static final int TEST_MIN_5G_RSSI = -65;
+    private static final int TEST_VALUE = 42;
+
+    private PnoNetwork mPnoNetwork1;
+    private PnoNetwork mPnoNetwork2;
+
+    @Before
+    public void setUp() {
+        mPnoNetwork1 = new PnoNetwork();
+        mPnoNetwork1.ssid = TEST_SSID_1;
+        mPnoNetwork1.isHidden = true;
+        mPnoNetwork1.frequencies = TEST_FREQUENCIES_1;
+
+        mPnoNetwork2 = new PnoNetwork();
+        mPnoNetwork2.ssid = TEST_SSID_2;
+        mPnoNetwork2.isHidden = false;
+        mPnoNetwork2.frequencies = TEST_FREQUENCIES_2;
+    }
+
+    /**
+     *  PnoSettings object can be serialized and deserialized, while keeping the
+     *  values unchanged.
+     */
+    @Test
+    public void canSerializeAndDeserialize() {
+        PnoSettings pnoSettings = new PnoSettings();
+        pnoSettings.intervalMs = TEST_INTERVAL_MS;
+        pnoSettings.min2gRssi = TEST_MIN_2G_RSSI;
+        pnoSettings.min5gRssi = TEST_MIN_5G_RSSI;
+        pnoSettings.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+
+        Parcel parcel = Parcel.obtain();
+        pnoSettings.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        PnoSettings pnoSettingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel);
+
+        assertEquals(pnoSettings, pnoSettingsDeserialized);
+        assertEquals(pnoSettings.hashCode(), pnoSettingsDeserialized.hashCode());
+    }
+
+    /**
+     * Tests usage of {@link PnoSettings} as a HashMap key type.
+     */
+    @Test
+    public void testAsHashMapKey() {
+        PnoSettings pnoSettings1 = new PnoSettings();
+        pnoSettings1.intervalMs = TEST_INTERVAL_MS;
+        pnoSettings1.min2gRssi = TEST_MIN_2G_RSSI;
+        pnoSettings1.min5gRssi = TEST_MIN_5G_RSSI;
+        pnoSettings1.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+
+        PnoSettings pnoSettings2 = new PnoSettings();
+        pnoSettings2.intervalMs = TEST_INTERVAL_MS;
+        pnoSettings2.min2gRssi = TEST_MIN_2G_RSSI;
+        pnoSettings2.min5gRssi = TEST_MIN_5G_RSSI;
+        pnoSettings2.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+
+        assertEquals(pnoSettings1, pnoSettings2);
+        assertEquals(pnoSettings1.hashCode(), pnoSettings2.hashCode());
+
+        HashMap<PnoSettings, Integer> map = new HashMap<>();
+        map.put(pnoSettings1, TEST_VALUE);
+
+        assertEquals(TEST_VALUE, map.get(pnoSettings2).intValue());
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java b/wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java
new file mode 100644
index 0000000..ef59839
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.wificond;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.wifi.IWifiScannerImpl;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * Unit tests for {@link android.net.wifi.wificond.SingleScanSettingsResult}.
+ */
+@SmallTest
+public class SingleScanSettingsTest {
+
+    private static final byte[] TEST_SSID_1 =
+            new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+    private static final byte[] TEST_SSID_2 =
+            new byte[] {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'T', 'e', 's', 't'};
+    private static final int TEST_FREQUENCY_1 = 2456;
+    private static final int TEST_FREQUENCY_2 = 5215;
+    private static final int TEST_VALUE = 42;
+
+    private ChannelSettings mChannelSettings1;
+    private ChannelSettings mChannelSettings2;
+    private HiddenNetwork mHiddenNetwork1;
+    private HiddenNetwork mHiddenNetwork2;
+
+    @Before
+    public void setUp() {
+        mChannelSettings1 = new ChannelSettings();
+        mChannelSettings1.frequency = TEST_FREQUENCY_1;
+        mChannelSettings2 = new ChannelSettings();
+        mChannelSettings2.frequency = TEST_FREQUENCY_2;
+
+        mHiddenNetwork1 = new HiddenNetwork();
+        mHiddenNetwork1.ssid = TEST_SSID_1;
+        mHiddenNetwork2 = new HiddenNetwork();
+        mHiddenNetwork2.ssid = TEST_SSID_2;
+    }
+
+    /**
+     *  SingleScanSettings object can be serialized and deserialized, while keeping the
+     *  values unchanged.
+     */
+    @Test
+    public void canSerializeAndDeserialize() {
+        SingleScanSettings scanSettings = new SingleScanSettings();
+        scanSettings.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+
+        scanSettings.channelSettings =
+                new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+        scanSettings.hiddenNetworks =
+                new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+        Parcel parcel = Parcel.obtain();
+        scanSettings.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        SingleScanSettings scanSettingsDeserialized =
+                SingleScanSettings.CREATOR.createFromParcel(parcel);
+
+        assertEquals(scanSettings, scanSettingsDeserialized);
+        assertEquals(scanSettings.hashCode(), scanSettingsDeserialized.hashCode());
+    }
+
+    /**
+     * Tests usage of {@link SingleScanSettings} as a HashMap key type.
+     */
+    @Test
+    public void testAsHashMapKey() {
+        SingleScanSettings scanSettings1 = new SingleScanSettings();
+        scanSettings1.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+        scanSettings1.channelSettings =
+                new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+        scanSettings1.hiddenNetworks =
+                new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+        SingleScanSettings scanSettings2 = new SingleScanSettings();
+        scanSettings2.scanType = IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
+        scanSettings2.channelSettings =
+                new ArrayList<>(Arrays.asList(mChannelSettings1, mChannelSettings2));
+        scanSettings2.hiddenNetworks =
+                new ArrayList<>(Arrays.asList(mHiddenNetwork1, mHiddenNetwork2));
+
+        assertEquals(scanSettings1, scanSettings2);
+        assertEquals(scanSettings1.hashCode(), scanSettings2.hashCode());
+
+        HashMap<SingleScanSettings, Integer> map = new HashMap<>();
+        map.put(scanSettings1, TEST_VALUE);
+
+        assertEquals(TEST_VALUE, map.get(scanSettings2).intValue());
+    }
+}