Merge "Add @UnsupportedAppUsage to test apis that are known to be used by apps."
diff --git a/Android.bp b/Android.bp
index 7903742..6e3799b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -463,13 +463,6 @@
     defaults: ["framework-defaults"],
     srcs: [":framework-all-sources"],
     installable: false,
-}
-
-java_library {
-    name: "framework-annotation-proc",
-    defaults: ["framework-aidl-export-defaults"],
-    srcs: [":framework-all-sources"],
-    installable: false,
     plugins: [
         "unsupportedappusage-annotation-processor",
         "compat-changeid-annotation-processor",
@@ -478,7 +471,7 @@
 
 platform_compat_config {
     name: "framework-platform-compat-config",
-    src: ":framework-annotation-proc",
+    src: ":framework-all",
 }
 
 // A library including just UnsupportedAppUsage.java classes.
@@ -760,6 +753,46 @@
     },
 }
 
+filegroup {
+    name: "incremental_aidl",
+    srcs: [
+        "core/java/android/os/incremental/IIncrementalService.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",
+    ],
+    path: "core/java",
+}
+
+filegroup {
+    name: "incremental_data_loader_aidl",
+    srcs: [
+        "core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl",
+        "core/java/android/service/incremental/IIncrementalDataLoaderService.aidl",
+    ],
+    path: "core/java",
+}
+
+aidl_interface {
+    name: "libincremental_aidl",
+    srcs: [
+        ":incremental_aidl",
+        ":incremental_data_loader_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+        },
+    },
+    api_dir: "aidl/incremental",
+}
 
 gensrcs {
     name: "gen-platform-proto-constants",
@@ -968,21 +1001,6 @@
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
     "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*"
 
-// http://b/129765390 Rewrite links to "platform" or "technotes" folders
-// which are siblings (and thus outside of) {@docRoot}.
-//
-// We have to escape \ as \\ and $ as $$ here because they get resolved by
-// different layers of the build tooling. The arguments are wrapped in '' so
-// that the shell doesn't add yet another level of escaping.
-metalava_framework_docs_args += " --replace-documentation " +
-    // packages whose descendants to apply replacement to (all packages from
-    // libcore/ojluni/src/main/java that contribute to documentation).
-    "com.sun:java:javax:jdk.net:sun " +
-    // regex of the string to replace
-    "'(<a\\s+href\\s?=[\\*\\s]*\")(?:(?:\\{@docRoot\\}/\\.\\./)|(?:(?:\\.\\./)+))((?:platform|technotes).+)\">' " +
-    // replacement (with $1, $2 backreferences to the regex groups)
-    "'$$1https://docs.oracle.com/javase/8/docs/$$2\">' "
-
 packages_to_document = [
     "android",
     "dalvik",
@@ -1577,7 +1595,7 @@
 
 genrule {
     name: "framework-annotation-proc-index",
-    srcs: [":framework-annotation-proc"],
+    srcs: [":framework-all"],
     cmd: "unzip -qp $(in) unsupportedappusage/unsupportedappusage_index.csv > $(out)",
     out: ["unsupportedappusage_index.csv"],
     dist: {
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 1b28913..478cfc1 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -25,4 +25,9 @@
         <option name="package" value="com.android.perftests.core" />
         <option name="hidden-api-checks" value="false"/>
     </test>
+
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="directory-keys" value="/data/local/CorePerfTests" />
+        <option name="collect-on-run-ended-only" value="true" />
+    </metrics_collector>
 </configuration>
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
index f43bdf8..f32bf9a 100644
--- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
@@ -111,11 +111,9 @@
 
     private static class RelayoutRunner {
         final Rect mOutFrame = new Rect();
-        final Rect mOutOverscanInsets = new Rect();
         final Rect mOutContentInsets = new Rect();
         final Rect mOutVisibleInsets = new Rect();
         final Rect mOutStableInsets = new Rect();
-        final Rect mOutOutsets = new Rect();
         final Rect mOutBackDropFrame = new Rect();
         final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
                 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
@@ -149,8 +147,8 @@
             while (state.keepRunning()) {
                 session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
                         mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
-                        mOutOverscanInsets, mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
-                        mOutOutsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
+                        mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
+                        mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
                         mOutSurfaceControl, mOutInsetsState);
             }
         }
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index 27790e6..4ac3adf 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -44,7 +44,11 @@
 import org.junit.Test;
 
 @LargeTest
-public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
+public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
+        implements ManualBenchmarkState.CustomizedIterationListener {
+
+    private static final int PROFILED_ITERATIONS = 2;
+
     @Rule
     public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
 
@@ -59,10 +63,24 @@
         sUiAutomation.dropShellPermissionIdentity();
     }
 
+    /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */
+    @Override
+    public void onStart(int iteration) {
+        startProfiling(WindowAddRemovePerfTest.class.getSimpleName()
+                + "_MethodTracing_" + iteration + ".trace");
+    }
+
+    @Override
+    public void onFinished(int iteration) {
+        stopProfiling();
+    }
+
     @Test
     @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
     public void testAddRemoveWindow() throws Throwable {
-        new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(PROFILED_ITERATIONS, this);
+        new TestWindow().runBenchmark(state);
     }
 
     private static class TestWindow extends BaseIWindow {
@@ -70,7 +88,6 @@
         final Rect mOutFrame = new Rect();
         final Rect mOutContentInsets = new Rect();
         final Rect mOutStableInsets = new Rect();
-        final Rect mOutOutsets = new Rect();
         final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
                 new DisplayCutout.ParcelableWrapper();
         final InsetsState mOutInsetsState = new InsetsState();
@@ -92,7 +109,7 @@
                 long startTime = SystemClock.elapsedRealtimeNanos();
                 session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
                         Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
-                        mOutOutsets, mOutDisplayCutout, inputChannel, mOutInsetsState);
+                        mOutDisplayCutout, inputChannel, mOutInsetsState);
                 final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
                 state.addExtraResult("add", elapsedTimeNsOfAdd);
 
@@ -102,6 +119,7 @@
                 state.addExtraResult("remove", elapsedTimeNsOfRemove);
 
                 elapsedTimeNs = elapsedTimeNsOfAdd + elapsedTimeNsOfRemove;
+                inputChannel.dispose();
             }
         }
     }
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index 4d278c3..62e9ba8 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -21,6 +21,7 @@
 import android.app.Activity;
 import android.app.UiAutomation;
 import android.content.Intent;
+import android.os.ParcelFileDescriptor;
 import android.perftests.utils.PerfTestActivity;
 
 import androidx.test.rule.ActivityTestRule;
@@ -32,6 +33,10 @@
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 public class WindowManagerPerfTestBase {
@@ -40,16 +45,54 @@
     static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
     static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
 
+    /**
+     * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory
+     * is in /data because while enabling method profling of system server, it cannot write the
+     * trace to external storage.
+     */
+    static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests");
+
     @BeforeClass
     public static void setUpOnce() {
+        if (!BASE_OUT_PATH.exists()) {
+            executeShellCommand("mkdir -p " + BASE_OUT_PATH);
+        }
         // In order to be closer to the real use case.
-        sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        sUiAutomation.executeShellCommand("wm dismiss-keyguard");
+        executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        executeShellCommand("wm dismiss-keyguard");
         getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN)
                 .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
     }
 
     /**
+     * Executes shell command with reading the output. It may also used to block until the current
+     * command is completed.
+     */
+    static ByteArrayOutputStream executeShellCommand(String command) {
+        final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand(command);
+        final byte[] buf = new byte[512];
+        final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        int bytesRead;
+        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            while ((bytesRead = fis.read(buf)) != -1) {
+                bytes.write(buf, 0, bytesRead);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return bytes;
+    }
+
+    /** Starts method tracing on system server. */
+    void startProfiling(String subPath) {
+        executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath));
+    }
+
+    void stopProfiling() {
+        executeShellCommand("am profile stop system");
+    }
+
+    /**
      * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage.
      */
     static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
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 a83254b..b075239 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -88,6 +88,15 @@
         int[] percentiles() default {};
     }
 
+    /** The interface to receive the events of customized iteration. */
+    public interface CustomizedIterationListener {
+        /** The customized iteration starts. */
+        void onStart(int iteration);
+
+        /** The customized iteration finished. */
+        void onFinished(int iteration);
+    }
+
     /** It means the entire {@link StatsReport} is not given. */
     private static final int DEFAULT_STATS_REPORT = -2;
 
@@ -105,7 +114,8 @@
     private static final int NOT_STARTED = 0;  // The benchmark has not started yet.
     private static final int WARMUP = 1; // The benchmark is warming up.
     private static final int RUNNING = 2;  // The benchmark is running.
-    private static final int FINISHED = 3;  // The benchmark has stopped.
+    private static final int RUNNING_CUSTOMIZED = 3;  // Running for customized measurement.
+    private static final int FINISHED = 4;  // The benchmark has stopped.
 
     private int mState = NOT_STARTED;  // Current benchmark state.
 
@@ -116,6 +126,14 @@
 
     private int mMaxIterations = 0;
 
+    /**
+     * Additinal iteration that used to apply customized measurement. The result during these
+     * iterations won't be counted into {@link #mStats}.
+     */
+    private int mMaxCustomizedIterations;
+    private int mCustomizedIterations;
+    private CustomizedIterationListener mCustomizedIterationListener;
+
     // Individual duration in nano seconds.
     private ArrayList<Long> mResults = new ArrayList<>();
 
@@ -189,10 +207,25 @@
                 final boolean keepRunning = mResults.size() < mMaxIterations;
                 if (!keepRunning) {
                     mStats = new Stats(mResults);
+                    if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) {
+                        mState = RUNNING_CUSTOMIZED;
+                        mCustomizedIterationListener.onStart(mCustomizedIterations);
+                        return true;
+                    }
                     mState = FINISHED;
                 }
                 return keepRunning;
             }
+            case RUNNING_CUSTOMIZED: {
+                mCustomizedIterationListener.onFinished(mCustomizedIterations);
+                mCustomizedIterations++;
+                if (mCustomizedIterations >= mMaxCustomizedIterations) {
+                    mState = FINISHED;
+                    return false;
+                }
+                mCustomizedIterationListener.onStart(mCustomizedIterations);
+                return true;
+            }
             case FINISHED:
                 throw new IllegalStateException("The benchmark has finished.");
             default:
@@ -210,11 +243,21 @@
     }
 
     /**
-     * Adds additional result while this benchmark isn't warming up. It is used when a sequence of
-     * operations is executed consecutively, the duration of each operation can also be recorded.
+     * This is used to run the benchmark with more information by enabling some debug mechanism but
+     * we don't want to account the special runs (slower) in the stats report.
+     */
+    public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) {
+        mMaxCustomizedIterations = iterations;
+        mCustomizedIterationListener = listener;
+    }
+
+    /**
+     * Adds additional result while this benchmark isn't warming up or running in customized state.
+     * It is used when a sequence of operations is executed consecutively, the duration of each
+     * operation can also be recorded.
      */
     public void addExtraResult(String key, long duration) {
-        if (isWarmingUp()) {
+        if (isWarmingUp() || mState == RUNNING_CUSTOMIZED) {
             return;
         }
         if (mExtraResults == null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 4e96f5e..593e494 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -57,7 +57,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -2689,12 +2688,10 @@
         }
 
         @Override
-        protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
-                @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
-                @NonNull String[] args) {
+        protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+                @NonNull FileDescriptor err, @NonNull String[] args) {
             return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
-                    this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
-                    args);
+                    this, in, out, err, args);
         }
 
 
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 1e4861a..82292cf 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -578,7 +578,7 @@
                 }
             }
         } catch (IOException | XmlPullParserException e) {
-            Slog.e(TAG, "Unable to read app idle file for user " + userId);
+            Slog.e(TAG, "Unable to read app idle file for user " + userId, e);
         } finally {
             IoUtils.closeQuietly(fis);
         }
@@ -608,6 +608,11 @@
             final int N = userHistory.size();
             for (int i = 0; i < N; i++) {
                 String packageName = userHistory.keyAt(i);
+                // Skip any unexpected null package names
+                if (packageName == null) {
+                    Slog.w(TAG, "Skipping App Idle write for unexpected null package");
+                    continue;
+                }
                 AppUsageHistory history = userHistory.valueAt(i);
                 xml.startTag(null, TAG_PACKAGE);
                 xml.attribute(null, ATTR_NAME, packageName);
@@ -641,7 +646,7 @@
             appIdleFile.finishWrite(fos);
         } catch (Exception e) {
             appIdleFile.failWrite(fos);
-            Slog.e(TAG, "Error writing app idle file for user " + userId);
+            Slog.e(TAG, "Error writing app idle file for user " + userId, e);
         }
     }
 
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 518a29c..d879273 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -18,7 +18,6 @@
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
-import static android.os.Process.getPidsForCommands;
 import static android.os.Process.getUidForPid;
 import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
 import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
@@ -27,6 +26,7 @@
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.ProcfsMemoryUtil.forEachPid;
 import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
 import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 
@@ -144,6 +144,8 @@
 import com.android.server.storage.DiskStatsFileLogger;
 import com.android.server.storage.DiskStatsLoggingService;
 
+import com.google.android.collect.Sets;
+
 import libcore.io.IoUtils;
 
 import org.json.JSONArray;
@@ -163,6 +165,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -216,7 +219,7 @@
      * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns
      * /system/bin/statsd for the stats daemon.
      */
-    private static final String[] MEMORY_INTERESTING_NATIVE_PROCESSES = new String[]{
+    private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet(
             "/system/bin/statsd",  // Stats daemon.
             "/system/bin/surfaceflinger",
             "/system/bin/apexd",  // APEX daemon.
@@ -239,8 +242,7 @@
             "/system/bin/traced_probes",  // Perfetto.
             "webview_zygote",
             "zygote",
-            "zygote64",
-    };
+            "zygote64");
     /**
      * Lowest available uid for apps.
      *
@@ -1220,27 +1222,28 @@
             e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
             pulledData.add(e);
         }
-        int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
-        for (int pid : pids) {
-            final String processName = readCmdlineFromProcfs(pid);
+        forEachPid((pid, cmdLine) -> {
+            if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+                return;
+            }
             final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
             if (snapshot == null) {
-                continue;
+                return;
             }
             // Sometimes we get here a process that is not included in the whitelist. It comes
             // from forking the zygote for an app. We can ignore that sample because this process
             // is collected by ProcessMemoryState.
             if (isAppUid(snapshot.uid)) {
-                continue;
+                return;
             }
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(snapshot.uid);
-            e.writeString(processName);
+            e.writeString(cmdLine);
             // RSS high-water mark in bytes.
             e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L);
             e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
             pulledData.add(e);
-        }
+        });
         // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.
         SystemProperties.set("sys.rss_hwm_reset.on", "1");
     }
@@ -1267,22 +1270,23 @@
             e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
             pulledData.add(e);
         }
-        int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
-        for (int pid : pids) {
-            final String processName = readCmdlineFromProcfs(pid);
+        forEachPid((pid, cmdLine) -> {
+            if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+                return;
+            }
             final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
             if (snapshot == null) {
-                continue;
+                return;
             }
             // Sometimes we get here a process that is not included in the whitelist. It comes
             // from forking the zygote for an app. We can ignore that sample because this process
             // is collected by ProcessMemoryState.
             if (isAppUid(snapshot.uid)) {
-                continue;
+                return;
             }
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(snapshot.uid);
-            e.writeString(processName);
+            e.writeString(cmdLine);
             e.writeInt(pid);
             e.writeInt(-1001);  // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
             e.writeInt(snapshot.rssInKilobytes);
@@ -1290,7 +1294,7 @@
             e.writeInt(snapshot.swapInKilobytes);
             e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
             pulledData.add(e);
-        }
+        });
     }
 
     private static boolean isAppUid(int uid) {
diff --git a/api/current.txt b/api/current.txt
index 81cf7cf..41e0daa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1597,7 +1597,7 @@
     field public static final int windowMinWidthMinor = 16843607; // 0x1010357
     field public static final int windowNoDisplay = 16843294; // 0x101021e
     field public static final int windowNoTitle = 16842838; // 0x1010056
-    field public static final int windowOverscan = 16843727; // 0x10103cf
+    field @Deprecated public static final int windowOverscan = 16843727; // 0x10103cf
     field public static final int windowReenterTransition = 16843951; // 0x10104af
     field public static final int windowReturnTransition = 16843950; // 0x10104ae
     field public static final int windowSharedElementEnterTransition = 16843833; // 0x1010439
@@ -2333,13 +2333,13 @@
     field public static final int Theme_Material_Light_LightStatusBar = 16974549; // 0x10302d5
     field public static final int Theme_Material_Light_NoActionBar = 16974401; // 0x1030241
     field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974402; // 0x1030242
-    field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
+    field @Deprecated public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
     field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974404; // 0x1030244
     field public static final int Theme_Material_Light_Panel = 16974405; // 0x1030245
     field public static final int Theme_Material_Light_Voice = 16974406; // 0x1030246
     field public static final int Theme_Material_NoActionBar = 16974382; // 0x103022e
     field public static final int Theme_Material_NoActionBar_Fullscreen = 16974383; // 0x103022f
-    field public static final int Theme_Material_NoActionBar_Overscan = 16974384; // 0x1030230
+    field @Deprecated public static final int Theme_Material_NoActionBar_Overscan = 16974384; // 0x1030230
     field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974385; // 0x1030231
     field public static final int Theme_Material_Panel = 16974386; // 0x1030232
     field public static final int Theme_Material_Settings = 16974387; // 0x1030233
@@ -23164,6 +23164,7 @@
 
   public class LocationManager {
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
@@ -23194,6 +23195,7 @@
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
     method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
     method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
     method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
     method public void removeTestProvider(@NonNull String);
@@ -38960,6 +38962,7 @@
     field public static final String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
     field public static final String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
     field public static final String ACTION_NOTIFICATION_ASSISTANT_SETTINGS = "android.settings.NOTIFICATION_ASSISTANT_SETTINGS";
+    field public static final String ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS = "android.settings.NOTIFICATION_LISTENER_DETAIL_SETTINGS";
     field public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
     field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
     field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -38999,6 +39002,7 @@
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+    field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
     field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
     field public static final String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
     field public static final String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
@@ -52272,7 +52276,7 @@
     field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
     field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
     field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
-    field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
+    field @Deprecated public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
     field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
     field public static final int FLAG_LOCAL_FOCUS_MODE = 268435456; // 0x10000000
diff --git a/api/removed.txt b/api/removed.txt
index c348ed9..e0e26f7 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -217,11 +217,6 @@
     method @Deprecated public void removeVerticalAccuracy();
   }
 
-  public class LocationManager {
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
-    method @Deprecated public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
-  }
-
 }
 
 package android.media {
diff --git a/api/system-current.txt b/api/system-current.txt
index d5f544c..c73a525 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6410,6 +6410,10 @@
 
 package android.security.keystore {
 
+  public class AndroidKeyStoreProvider extends java.security.Provider {
+    method @NonNull public static java.security.KeyStore getKeyStoreForUid(int) throws java.security.KeyStoreException, java.security.NoSuchProviderException;
+  }
+
   public abstract class AttestationUtils {
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
@@ -6423,6 +6427,10 @@
     ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
   }
 
+  public static final class KeyGenParameterSpec.Builder {
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
+  }
+
 }
 
 package android.security.keystore.recovery {
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 5e156bb..f9f11b2 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -59,10 +59,11 @@
     return JenkinsHashWhiten(hash);
 }
 
-bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, Value* output) {
+bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values,
+                  FieldValue* output) {
     for (const auto& value : values) {
         if (value.mField.matches(matcherField)) {
-            (*output) = value.mValue;
+            (*output) = value;
             return true;
         }
     }
@@ -106,15 +107,34 @@
 
     size_t count = conditionDimension->getValues().size();
     if (count != links.conditionFields.size()) {
-        // ALOGE("WTF condition link is bad");
         return;
     }
 
     for (size_t i = 0; i < count; i++) {
         conditionDimension->mutableValue(i)->mField.setField(
-            links.conditionFields[i].mMatcher.getField());
+                links.conditionFields[i].mMatcher.getField());
         conditionDimension->mutableValue(i)->mField.setTag(
-            links.conditionFields[i].mMatcher.getTag());
+                links.conditionFields[i].mMatcher.getTag());
+    }
+}
+
+void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
+                          HashableDimensionKey* statePrimaryKey) {
+    // First, get the dimension from the event using the "what" fields from the
+    // MetricStateLinks.
+    filterValues(link.metricFields, eventValues, statePrimaryKey);
+
+    // Then check that the statePrimaryKey size equals the number of state fields
+    size_t count = statePrimaryKey->getValues().size();
+    if (count != link.stateFields.size()) {
+        return;
+    }
+
+    // For each dimension Value in the statePrimaryKey, set the field and tag
+    // using the state atom fields from MetricStateLinks.
+    for (size_t i = 0; i < count; i++) {
+        statePrimaryKey->mutableValue(i)->mField.setField(link.stateFields[i].mMatcher.getField());
+        statePrimaryKey->mutableValue(i)->mField.setTag(link.stateFields[i].mMatcher.getTag());
     }
 }
 
@@ -185,11 +205,11 @@
 
 bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
     return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
-           mDimensionKeyInCondition == that.getDimensionKeyInCondition();
+           mStateValuesKey == that.getStateValuesKey();
 };
 
 string MetricDimensionKey::toString() const {
-    return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString();
+    return mDimensionKeyInWhat.toString() + mStateValuesKey.toString();
 }
 
 bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
@@ -199,7 +219,7 @@
         return false;
     }
 
-    return mDimensionKeyInCondition < that.getDimensionKeyInCondition();
+    return mStateValuesKey < that.getStateValuesKey();
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index a123850..b9b86ce 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -34,6 +34,12 @@
     std::vector<Matcher> conditionFields;
 };
 
+struct Metric2State {
+    int32_t stateAtomId;
+    std::vector<Matcher> metricFields;
+    std::vector<Matcher> stateFields;
+};
+
 class HashableDimensionKey {
 public:
     explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
@@ -76,17 +82,16 @@
 };
 
 class MetricDimensionKey {
- public:
+public:
     explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
-                                const HashableDimensionKey& dimensionKeyInCondition)
-        : mDimensionKeyInWhat(dimensionKeyInWhat),
-          mDimensionKeyInCondition(dimensionKeyInCondition) {};
+                                const HashableDimensionKey& stateValuesKey)
+        : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){};
 
     MetricDimensionKey(){};
 
     MetricDimensionKey(const MetricDimensionKey& that)
         : mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
-          mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {};
+          mStateValuesKey(that.getStateValuesKey()){};
 
     MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;
 
@@ -96,25 +101,25 @@
         return mDimensionKeyInWhat;
     }
 
-    inline const HashableDimensionKey& getDimensionKeyInCondition() const {
-        return mDimensionKeyInCondition;
+    inline const HashableDimensionKey& getStateValuesKey() const {
+        return mStateValuesKey;
     }
 
-    inline void setDimensionKeyInCondition(const HashableDimensionKey& key) {
-        mDimensionKeyInCondition = key;
+    inline void setStateValuesKey(const HashableDimensionKey& key) {
+        mStateValuesKey = key;
     }
 
-    bool hasDimensionKeyInCondition() const {
-        return mDimensionKeyInCondition.getValues().size() > 0;
+    bool hasStateValuesKey() const {
+        return mStateValuesKey.getValues().size() > 0;
     }
 
     bool operator==(const MetricDimensionKey& that) const;
 
     bool operator<(const MetricDimensionKey& that) const;
 
-  private:
-      HashableDimensionKey mDimensionKeyInWhat;
-      HashableDimensionKey mDimensionKeyInCondition;
+private:
+    HashableDimensionKey mDimensionKeyInWhat;
+    HashableDimensionKey mStateValuesKey;
 };
 
 android::hash_t hashDimension(const HashableDimensionKey& key);
@@ -124,7 +129,7 @@
  * The value of the FieldValue is output.
  */
 bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
-                  Value* output);
+                  FieldValue* output);
 
 /**
  * Creating HashableDimensionKeys from FieldValues using matcher.
@@ -152,6 +157,13 @@
                               const Metric2Condition& links,
                               HashableDimensionKey* conditionDimension);
 
+/**
+ * Get dimension values using metric's "what" fields and fill statePrimaryKey's
+ * mField information using "state" fields.
+ */
+void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
+                          HashableDimensionKey* statePrimaryKey);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
@@ -172,7 +184,7 @@
 struct hash<MetricDimensionKey> {
     std::size_t operator()(const MetricDimensionKey& key) const {
         android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
-        hash = android::JenkinsHashMix(hash, hashDimension(key.getDimensionKeyInCondition()));
+        hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
         return android::JenkinsHashWhiten(hash);
     }
 };
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 17f2770..b41771d 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -263,9 +263,10 @@
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
 
-    FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
 
     FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
     FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 4a06387..c29b32c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -57,10 +57,9 @@
 const int FIELD_ID_DATA = 1;
 // for CountMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
+const int FIELD_ID_SLICE_BY_STATE = 6;
 const int FIELD_ID_BUCKET_INFO = 3;
 const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
 // for CountBucketInfo
 const int FIELD_ID_COUNT = 3;
 const int FIELD_ID_BUCKET_NUM = 4;
@@ -102,7 +101,13 @@
         mConditionSliced = true;
     }
 
-    // TODO(tsaichristine): b/142124705 handle metric state links
+    for (const auto& stateLink : metric.state_link()) {
+        Metric2State ms;
+        ms.stateAtomId = stateLink.state_atom_id();
+        translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
+        translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
+        mMetric2StateLinks.push_back(ms);
+    }
 
     flushIfNeededLocked(startTimeNs);
     // Adjust start for partial bucket
@@ -132,10 +137,9 @@
             (unsigned long)mCurrentSlicedCounter->size());
     if (verbose) {
         for (const auto& it : *mCurrentSlicedCounter) {
-            fprintf(out, "\t(what)%s\t(condition)%s  %lld\n",
-                it.first.getDimensionKeyInWhat().toString().c_str(),
-                it.first.getDimensionKeyInCondition().toString().c_str(),
-                (unsigned long long)it.second);
+            fprintf(out, "\t(what)%s\t(state)%s  %lld\n",
+                    it.first.getDimensionKeyInWhat().toString().c_str(),
+                    it.first.getStateValuesKey().toString().c_str(), (unsigned long long)it.second);
         }
     }
 }
@@ -196,22 +200,16 @@
                     FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
             writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
             protoOutput->end(dimensionToken);
-
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                uint64_t dimensionInConditionToken = protoOutput->start(
-                        FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
-                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
-                                      str_set, protoOutput);
-                protoOutput->end(dimensionInConditionToken);
-            }
         } else {
             writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
                                            FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
-                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
-                                               str_set, protoOutput);
-            }
+        }
+        // Then fill slice_by_state.
+        for (auto state : dimensionKey.getStateValuesKey().getValues()) {
+            uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                     FIELD_ID_SLICE_BY_STATE);
+            writeStateToProto(state, protoOutput);
+            protoOutput->end(stateToken);
         }
         // Then fill bucket_info (CountBucketInfo).
         for (const auto& bucket : counter.second) {
@@ -282,7 +280,7 @@
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
     flushIfNeededLocked(eventTimeNs);
 
-    if (condition == false) {
+    if (!condition) {
         return;
     }
 
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 61e0892..8b17d88 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -52,7 +52,7 @@
 
     virtual ~CountMetricProducer();
 
-    void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
+    void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, int oldState,
                         int newState) override;
 
 protected:
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index ab2a1c3..fee5e6e 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -53,10 +53,8 @@
 const int FIELD_ID_DATA = 1;
 // for DurationMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
 const int FIELD_ID_BUCKET_INFO = 3;
 const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
 // for DurationBucketInfo
 const int FIELD_ID_DURATION = 3;
 const int FIELD_ID_BUCKET_NUM = 4;
@@ -120,9 +118,8 @@
     mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
     if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
             mMetric2ConditionLinks.size() == 1) {
-        mHasLinksToAllConditionDimensionsInTracker =
-            mWizard->equalOutputDimensions(mConditionTrackerIndex,
-                                           mMetric2ConditionLinks.begin()->conditionFields);
+        mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions(
+                mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields);
     }
     flushIfNeededLocked(startTimeNs);
     // Adjust start for partial bucket
@@ -206,8 +203,7 @@
         mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
         for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
             HashableDimensionKey linkedConditionDimensionKey;
-            getDimensionForCondition(whatIt.first.getValues(),
-                                     mMetric2ConditionLinks[0],
+            getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
                                      &linkedConditionDimensionKey);
             if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
                     trueConditionDimensions.end()) {
@@ -222,8 +218,7 @@
         if (currentUnSlicedPartCondition) {
             for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
                 HashableDimensionKey linkedConditionDimensionKey;
-                getDimensionForCondition(whatIt.first.getValues(),
-                                         mMetric2ConditionLinks[0],
+                getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
                                          &linkedConditionDimensionKey);
                 if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
                         dimensionsChangedToTrue->end()) {
@@ -380,22 +375,9 @@
                     FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
             writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
             protoOutput->end(dimensionToken);
-
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                uint64_t dimensionInConditionToken = protoOutput->start(
-                        FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
-                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
-                                      str_set, protoOutput);
-                protoOutput->end(dimensionInConditionToken);
-            }
         } else {
             writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
                                            FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
-                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
-                                               str_set, protoOutput);
-            }
         }
         // Then fill bucket_info (DurationBucketInfo).
         for (const auto& bucket : pair.second) {
@@ -472,7 +454,7 @@
     if (verbose) {
         for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
             for (const auto& slice : whatIt.second) {
-                fprintf(out, "\t(what)%s\t(condition)%s\n", whatIt.first.toString().c_str(),
+                fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
                         slice.first.toString().c_str());
                 slice.second->dumpStates(out, verbose);
             }
@@ -483,8 +465,8 @@
 bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
     auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
     if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-        auto condIt = whatIt->second.find(newKey.getDimensionKeyInCondition());
-        if (condIt != whatIt->second.end()) {
+        auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
+        if (stateIt != whatIt->second.end()) {
             return false;
         }
         if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
@@ -493,8 +475,8 @@
                     mConfigKey, mMetricId, newTupleCount);
             // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
             if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-                ALOGE("DurationMetric %lld dropping data for condition dimension key %s",
-                    (long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str());
+                ALOGE("DurationMetric %lld dropping data for state values key %s",
+                      (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
                 StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
                 return true;
             }
@@ -521,24 +503,24 @@
                                               const ConditionKey& conditionKeys,
                                               bool condition, const LogEvent& event) {
     const auto& whatKey = eventKey.getDimensionKeyInWhat();
-    const auto& condKey = eventKey.getDimensionKeyInCondition();
+    const auto& stateKey = eventKey.getStateValuesKey();
 
     auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
     if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
         if (hitGuardRailLocked(eventKey)) {
             return;
         }
-        mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+        mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
     } else {
-        if (whatIt->second.find(condKey) == whatIt->second.end()) {
+        if (whatIt->second.find(stateKey) == whatIt->second.end()) {
             if (hitGuardRailLocked(eventKey)) {
                 return;
             }
-            mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+            mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
         }
     }
 
-    auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey);
+    auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
     if (mUseWhatDimensionAsInternalDimension) {
         it->second->noteStart(whatKey, condition,
                               event.GetElapsedTimestampNs(), conditionKeys);
@@ -597,8 +579,8 @@
         if (mUseWhatDimensionAsInternalDimension) {
             auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
             if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-                for (const auto& condIt : whatIt->second) {
-                    condIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
+                for (const auto& stateIt : whatIt->second) {
+                    stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
                 }
             }
             return;
@@ -611,9 +593,9 @@
 
         auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
         if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-            for (const auto& condIt : whatIt->second) {
-                condIt.second->noteStop(
-                    internalDimensionKey, event.GetElapsedTimestampNs(), false);
+            for (const auto& stateIt : whatIt->second) {
+                stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
+                                         false);
             }
         }
         return;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d0f88a8..64344e8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -56,10 +56,8 @@
 const int FIELD_ID_SKIPPED_END_MILLIS = 4;
 // for GaugeMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
 const int FIELD_ID_BUCKET_INFO = 3;
 const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
 // for GaugeBucketInfo
 const int FIELD_ID_ATOM = 3;
 const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
@@ -166,10 +164,9 @@
             (unsigned long)mCurrentSlicedBucket->size());
     if (verbose) {
         for (const auto& it : *mCurrentSlicedBucket) {
-            fprintf(out, "\t(what)%s\t(condition)%s  %d atoms\n",
-                it.first.getDimensionKeyInWhat().toString().c_str(),
-                it.first.getDimensionKeyInCondition().toString().c_str(),
-                (int)it.second.size());
+            fprintf(out, "\t(what)%s\t(states)%s  %d atoms\n",
+                    it.first.getDimensionKeyInWhat().toString().c_str(),
+                    it.first.getStateValuesKey().toString().c_str(), (int)it.second.size());
         }
     }
 }
@@ -238,22 +235,9 @@
                     FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
             writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
             protoOutput->end(dimensionToken);
-
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                uint64_t dimensionInConditionToken = protoOutput->start(
-                        FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
-                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
-                                      str_set, protoOutput);
-                protoOutput->end(dimensionInConditionToken);
-            }
         } else {
             writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
                                            FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
-                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
-                                               str_set, protoOutput);
-            }
         }
 
         // Then fill bucket_info (GaugeBucketInfo).
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 2a700ef..2c8f0e3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -16,8 +16,11 @@
 
 #define DEBUG false  // STOPSHIP if true
 #include "Log.h"
+
 #include "MetricProducer.h"
 
+#include "state/StateTracker.h"
+
 using android::util::FIELD_COUNT_REPEATED;
 using android::util::FIELD_TYPE_ENUM;
 using android::util::FIELD_TYPE_INT32;
@@ -92,9 +95,43 @@
         condition = mCondition == ConditionState::kTrue;
     }
 
+    // Stores atom id to primary key pairs for each state atom that the metric is
+    // sliced by.
+    std::map<int, HashableDimensionKey> statePrimaryKeys;
+
+    // For states with primary fields, use MetricStateLinks to get the primary
+    // field values from the log event. These values will form a primary key
+    // that will be used to query StateTracker for the correct state value.
+    for (const auto& stateLink : mMetric2StateLinks) {
+        getDimensionForState(event.getValues(), stateLink,
+                             &statePrimaryKeys[stateLink.stateAtomId]);
+    }
+
+    // For each sliced state, query StateTracker for the state value using
+    // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
+    //
+    // Expected functionality: for any case where the MetricStateLinks are
+    // initialized incorrectly (ex. # of state links != # of primary fields, no
+    // links are provided for a state with primary fields, links are provided
+    // in the wrong order, etc.), StateTracker will simply return kStateUnknown
+    // when queried using an incorrect key.
+    HashableDimensionKey stateValuesKey;
+    for (auto atomId : mSlicedStateAtoms) {
+        FieldValue value;
+        if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
+            // found a primary key for this state, query using the key
+            getMappedStateValue(atomId, statePrimaryKeys[atomId], &value);
+        } else {
+            // if no MetricStateLinks exist for this state atom,
+            // query using the default dimension key (empty HashableDimensionKey)
+            getMappedStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
+        }
+        stateValuesKey.addValue(value);
+    }
+
     HashableDimensionKey dimensionInWhat;
     filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
-    MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
+    MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
     onMatchedLogEventInternalLocked(
             matcherIndex, metricKey, conditionKey, condition, event);
 }
@@ -227,6 +264,31 @@
     }
 }
 
+void MetricProducer::getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
+                                         FieldValue* value) {
+    if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
+        value->mValue = Value(StateTracker::kStateUnknown);
+        ALOGW("StateTracker not found for state atom %d", atomId);
+        return;
+    }
+
+    // check if there is a state map for this atom
+    auto atomIt = mStateGroupMap.find(atomId);
+    if (atomIt == mStateGroupMap.end()) {
+        return;
+    }
+    auto valueIt = atomIt->second.find(value->mValue.int_value);
+    if (valueIt == atomIt->second.end()) {
+        // state map exists, but value was not put in a state group
+        // so set mValue to kStateUnknown
+        // TODO(tsaichristine): handle incomplete state maps
+        value->mValue.setInt(StateTracker::kStateUnknown);
+    } else {
+        // set mValue to group_id
+        value->mValue.setLong(valueIt->second);
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index a72de22..d7cbcc8 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -30,6 +30,7 @@
 #include "matchers/matcher_util.h"
 #include "packages/PackageInfoListener.h"
 #include "state/StateListener.h"
+#include "state/StateManager.h"
 
 namespace android {
 namespace os {
@@ -340,6 +341,12 @@
         return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
     }
 
+    // Query StateManager for original state value.
+    // If no state map exists for this atom, return the original value.
+    // Otherwise, return the group_id mapped to the atom and original value.
+    void getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
+                             FieldValue* value);
+
     const int64_t mMetricId;
 
     const ConfigKey mConfigKey;
@@ -392,14 +399,19 @@
     bool mIsActive;
 
     // The slice_by_state atom ids defined in statsd_config.
-    std::vector<int> mSlicedStateAtoms;
+    std::vector<int32_t> mSlicedStateAtoms;
 
     // Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>).
-    std::unordered_map<int, std::unordered_map<int, int64_t>> mStateGroupMap;
+    std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
 
-    FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+    // MetricStateLinks defined in statsd_config that link fields in the state
+    // atom to fields in the "what" atom.
+    std::vector<Metric2State> mMetric2StateLinks;
+
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
 
     FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
     FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d184121..286610a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -282,9 +282,10 @@
             TestActivationOnBootMultipleActivationsDifferentActivationTypes);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
 
-    FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
-    FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
 
     FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
     FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index f53a745..eb78ebc 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -59,10 +59,8 @@
 const int FIELD_ID_SKIPPED_END_MILLIS = 4;
 // for ValueMetricData
 const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
 const int FIELD_ID_BUCKET_INFO = 3;
 const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
 // for ValueBucketInfo
 const int FIELD_ID_VALUE_INDEX = 1;
 const int FIELD_ID_VALUE_LONG = 2;
@@ -266,21 +264,9 @@
                     protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
             writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
             protoOutput->end(dimensionToken);
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                uint64_t dimensionInConditionToken =
-                        protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
-                writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set,
-                                      protoOutput);
-                protoOutput->end(dimensionInConditionToken);
-            }
         } else {
             writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
                                            FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-            if (dimensionKey.hasDimensionKeyInCondition()) {
-                writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
-                                               FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set,
-                                               protoOutput);
-            }
         }
 
         // Then fill bucket_info (ValueBucketInfo).
@@ -586,10 +572,10 @@
     if (verbose) {
         for (const auto& it : mCurrentSlicedBucket) {
           for (const auto& interval : it.second) {
-            fprintf(out, "\t(what)%s\t(condition)%s  (value)%s\n",
-                    it.first.getDimensionKeyInWhat().toString().c_str(),
-                    it.first.getDimensionKeyInCondition().toString().c_str(),
-                    interval.value.toString().c_str());
+              fprintf(out, "\t(what)%s\t(states)%s  (value)%s\n",
+                      it.first.getDimensionKeyInWhat().toString().c_str(),
+                      it.first.getStateValuesKey().toString().c_str(),
+                      interval.value.toString().c_str());
           }
         }
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 33e162e..6e76717 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -472,11 +472,13 @@
                                         allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
                 return false;
             }
+        } else {
+            if (metric.state_link_size() > 0) {
+                ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state");
+                return false;
+            }
         }
 
-        // TODO(tsaichristine): add check for unequal number of MetricStateLinks
-        // and slice_by_states
-
         unordered_map<int, shared_ptr<Activation>> eventActivationMap;
         unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
         bool success = handleMetricActivation(config, metric.id(), metricIndex,
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
index a31690a..f2b9a6b 100644
--- a/cmds/statsd/src/state/StateListener.h
+++ b/cmds/statsd/src/state/StateListener.h
@@ -43,8 +43,8 @@
      * [oldState]: Previous state value before state change
      * [newState]: Current state value after state change
      */
-    virtual void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
-                                int newState) = 0;
+    virtual void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey,
+                                int oldState, int newState) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
index 95b2c76..2fa28c9 100644
--- a/cmds/statsd/src/state/StateManager.cpp
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -35,7 +35,7 @@
     }
 }
 
-bool StateManager::registerListener(int atomId, wp<StateListener> listener) {
+bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) {
     std::lock_guard<std::mutex> lock(mMutex);
 
     // Check if state tracker already exists
@@ -53,7 +53,7 @@
     return true;
 }
 
-void StateManager::unregisterListener(int atomId, wp<StateListener> listener) {
+void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener) {
     std::unique_lock<std::mutex> lock(mMutex);
 
     // Hold the sp<> until the lock is released so that ~StateTracker() is
@@ -77,13 +77,15 @@
     lock.unlock();
 }
 
-int StateManager::getStateValue(int atomId, const HashableDimensionKey& key) {
+bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key,
+                                 FieldValue* output) const {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mStateTrackers.find(atomId) != mStateTrackers.end()) {
-        return mStateTrackers[atomId]->getStateValue(key);
-    }
 
-    return StateTracker::kStateUnknown;
+    auto it = mStateTrackers.find(atomId);
+    if (it != mStateTrackers.end()) {
+        return it->second->getStateValue(key, output);
+    }
+    return false;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index 89ee6c0..272724c 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -42,26 +42,30 @@
     // Returns true if atomId is being tracked and is associated with a state
     // atom. StateManager notifies the correct StateTracker to register listener.
     // If the correct StateTracker does not exist, a new StateTracker is created.
-    bool registerListener(int atomId, wp<StateListener> listener);
+    bool registerListener(int32_t atomId, wp<StateListener> listener);
 
     // Notifies the correct StateTracker to unregister a listener
     // and removes the tracker if it no longer has any listeners.
-    void unregisterListener(int atomId, wp<StateListener> listener);
+    void unregisterListener(int32_t atomId, wp<StateListener> listener);
 
-    // Queries the correct StateTracker for the original/un-mapped state value
-    // that is mapped to the given query key.
-    // If the StateTracker doesn't exist, returns StateTracker::kStateUnknown.
-    int getStateValue(int atomId, const HashableDimensionKey& queryKey);
+    // Returns true if the StateTracker exists and queries for the
+    // original state value mapped to the given query key. The state value is
+    // stored and output in a FieldValue class.
+    // Returns false if the StateTracker doesn't exist.
+    bool getStateValue(int32_t atomId, const HashableDimensionKey& queryKey,
+                       FieldValue* output) const;
 
-    inline int getStateTrackersCount() {
+    inline int getStateTrackersCount() const {
         std::lock_guard<std::mutex> lock(mMutex);
         return mStateTrackers.size();
     }
 
-    inline int getListenersCount(int atomId) {
+    inline int getListenersCount(int32_t atomId) const {
         std::lock_guard<std::mutex> lock(mMutex);
-        if (mStateTrackers.find(atomId) != mStateTrackers.end()) {
-            return mStateTrackers[atomId]->getListenersCount();
+
+        auto it = mStateTrackers.find(atomId);
+        if (it != mStateTrackers.end()) {
+            return it->second->getListenersCount();
         }
         return -1;
     }
@@ -70,7 +74,7 @@
   mutable std::mutex mMutex;
 
   // Maps state atom ids to StateTrackers
-  std::unordered_map<int, sp<StateTracker>> mStateTrackers;
+  std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index 323fc0e..e6f6122 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -25,10 +25,8 @@
 namespace os {
 namespace statsd {
 
-StateTracker::StateTracker(const int atomId,
-                           const util::StateAtomFieldOptions& stateAtomInfo)
-  : mAtomId(atomId),
-    mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
+StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo)
+    : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
     // create matcher for each primary field
     // TODO(tsaichristine): b/142108433 handle when primary field is first uid in chain
     for (const auto& primary : stateAtomInfo.primaryFields) {
@@ -55,24 +53,26 @@
     }
 
     // parse event for state value
-    Value state;
-    int32_t stateValue;
-    if (!filterValues(mStateField, event.getValues(), &state) || state.getType() != INT) {
-        ALOGE("StateTracker error extracting state from log event. Type: %d", state.getType());
+    FieldValue stateValue;
+    int32_t state;
+    if (!filterValues(mStateField, event.getValues(), &stateValue) ||
+        stateValue.mValue.getType() != INT) {
+        ALOGE("StateTracker error extracting state from log event. Type: %d",
+              stateValue.mValue.getType());
         handlePartialReset(primaryKey);
         return;
     }
-    stateValue = state.int_value;
+    state = stateValue.mValue.int_value;
 
-    if (stateValue == mResetState) {
-        VLOG("StateTracker Reset state: %s", state.toString().c_str());
+    if (state == mResetState) {
+        VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
         handleReset();
     }
 
     // track and update state
     int32_t oldState = 0;
     int32_t newState = 0;
-    updateState(primaryKey, stateValue, &oldState, &newState);
+    updateState(primaryKey, state, &oldState, &newState);
 
     // notify all listeners if state has changed
     if (oldState != newState) {
@@ -96,18 +96,27 @@
     mListeners.erase(listener);
 }
 
-int StateTracker::getStateValue(const HashableDimensionKey& queryKey) const {
+bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
+    output->mField = mStateField.mMatcher;
+
+    // Check that the query key has the correct number of primary fields.
     if (queryKey.getValues().size() == mPrimaryFields.size()) {
         auto it = mStateMap.find(queryKey);
         if (it != mStateMap.end()) {
-            return it->second.state;
+            output->mValue = it->second.state;
+            return true;
         }
     } else if (queryKey.getValues().size() > mPrimaryFields.size()) {
         ALOGE("StateTracker query key size > primary key size is illegal");
     } else {
         ALOGE("StateTracker query key size < primary key size is not supported");
     }
-    return mDefaultState;
+
+    // Set the state value to unknown if:
+    // - query key size is incorrect
+    // - query key is not found in state map
+    output->mValue = StateTracker::kStateUnknown;
+    return false;
 }
 
 void StateTracker::handleReset() {
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index cfa9fd8..450412d 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -30,7 +30,7 @@
 
 class StateTracker : public virtual RefBase {
 public:
-    StateTracker(const int atomId, const util::StateAtomFieldOptions& stateAtomInfo);
+    StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo);
 
     virtual ~StateTracker(){};
 
@@ -45,10 +45,12 @@
 
     void unregisterListener(wp<StateListener> listener);
 
-    // Returns the state value mapped to the given query key.
+    // The output is a FieldValue object that has mStateField as the field and
+    // the original state value (found using the given query key) as the value.
+    //
     // If the key isn't mapped to a state or the key size doesn't match the
-    // primary key size, the default state is returned.
-    int getStateValue(const HashableDimensionKey& queryKey) const;
+    // number of primary fields, the output value is set to kStateUnknown.
+    bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const;
 
     inline int getListenersCount() const {
         return mListeners.size();
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index c22e3cc..76c1936 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -53,6 +53,11 @@
 
 const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
 
+// for StateValue Proto
+const int STATE_VALUE_ATOM_ID = 1;
+const int STATE_VALUE_CONTENTS_GROUP_ID = 2;
+const int STATE_VALUE_CONTENTS_VALUE = 3;
+
 // for PulledAtomStats proto
 const int FIELD_ID_PULLED_ATOM_STATS = 10;
 const int FIELD_ID_PULL_ATOM_ID = 1;
@@ -416,6 +421,23 @@
     protoOutput->end(atomToken);
 }
 
+void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput) {
+    protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_ATOM_ID, state.mField.getTag());
+
+    switch (state.mValue.getType()) {
+        case INT:
+            protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_CONTENTS_VALUE,
+                               state.mValue.int_value);
+            break;
+        case LONG:
+            protoOutput->write(FIELD_TYPE_INT64 | STATE_VALUE_CONTENTS_GROUP_ID,
+                               state.mValue.long_value);
+            break;
+        default:
+            break;
+    }
+}
+
 int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
     int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
     if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index bfb84cf..0a86363 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -40,6 +40,8 @@
 void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
                                util::ProtoOutputStream* protoOutput);
 
+void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput);
+
 // Convert the TimeUnit enum to the bucket size in millis with a guardrail on
 // bucket size.
 int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 0664867..a22805b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -178,7 +178,7 @@
 }
 
 message MetricStateLink {
-  optional int64 state = 1;
+  optional int32 state_atom_id = 1;
 
   optional FieldMatcher fields_in_what = 2;
 
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index f2c6f1a..f1320c2 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -52,7 +52,6 @@
 const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
 const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
 const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
-const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3;
 const int FIELD_ID_METRIC_VALUE_VALUE = 4;
 
 const int FIELD_ID_PACKAGE_INFO = 3;
@@ -84,10 +83,8 @@
     writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
     headerProto.end(dimToken);
 
+    // deprecated field
     // optional DimensionsValue dimension_in_condition = 3;
-    dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION);
-    writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto);
-    headerProto.end(dimToken);
 
     // optional int64 value = 4;
     headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
@@ -106,13 +103,6 @@
         }
     }
 
-    for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) {
-        int uid = getUidIfExists(dim);
-        if (uid > 2000) {
-            uids.insert(uid);
-        }
-    }
-
     if (!uids.empty()) {
         uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
         UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index 6591d69..0f51c1b 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -18,6 +18,7 @@
 
 #include "src/StatsLogProcessor.h"
 #include "src/state/StateManager.h"
+#include "src/state/StateTracker.h"
 #include "tests/statsd_test_util.h"
 
 namespace android {
@@ -26,8 +27,20 @@
 
 #ifdef __ANDROID__
 
-TEST(CountMetricE2eTest, TestWithSimpleState) {
-    // Initialize config
+const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
+const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
+
+/**
+ * Test a count metric that has one slice_by_state with no primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and no entries in mStateGroupMap.
+
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedState) {
+    // Initialize config.
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
@@ -37,30 +50,22 @@
     auto state = CreateScreenState();
     *config.add_state() = state;
 
-    // Create count metric that slices by screen state
+    // Create count metric that slices by screen state.
     int64_t metricId = 123456;
     auto countMetric = config.add_count_metric();
     countMetric->set_id(metricId);
     countMetric->set_what(syncStartMatcher.id());
-    countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     countMetric->add_slice_by_state(state.id());
 
-    // Initialize StatsLogProcessor
-    const int64_t baseTimeNs = 0;                                   // 0:00
-    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
     int uid = 12345;
     int64_t cfgId = 98765;
     ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were properly initialized.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1,
-              StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
 
     // Check that CountMetricProducer was initialized correctly.
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -69,12 +74,118 @@
     EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
     sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
     EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
     EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+
+    // Check that StateTrackers were initialized correctly.
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+    /*
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10 (minutes)
+    |-----------------------------|-----------------------------|--
+            x                x         x    x        x      x       (syncStartEvents)
+          |                                       |                 (ScreenIsOnEvent)
+                   |     |                                          (ScreenIsOffEvent)
+                                                        |           (ScreenUnknownEvent)
+    */
+    // Initialize log events - first bucket.
+    int appUid = 123;
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 50 * NS_PER_SEC));  // 1:00
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 75 * NS_PER_SEC));  // 1:25
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 350 * NS_PER_SEC));  // 6:00
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 400 * NS_PER_SEC));  // 6:50
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 450 * NS_PER_SEC));  // 7:40
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 475 * NS_PER_SEC));  // 8:05
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+                                          bucketStartTimeNs + 500 * NS_PER_SEC));  // 8:30
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 520 * NS_PER_SEC));  // 8:50
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
 }
 
-TEST(CountMetricE2eTest, TestWithMappedState) {
-    // Initialize config
+/**
+ * Test a count metric that has one slice_by_state with a mapping and no
+ * primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
+ *
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
+    // Initialize config.
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
@@ -84,30 +195,26 @@
     auto state = CreateScreenStateWithOnOffMap();
     *config.add_state() = state;
 
-    // Create count metric that slices by screen state with on/off map
+    // Create count metric that slices by screen state with on/off map.
     int64_t metricId = 123456;
     auto countMetric = config.add_count_metric();
     countMetric->set_id(metricId);
     countMetric->set_what(syncStartMatcher.id());
-    countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     countMetric->add_slice_by_state(state.id());
 
-    // Initialize StatsLogProcessor
-    const int64_t baseTimeNs = 0;                                   // 0:00
-    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
     int uid = 12345;
     int64_t cfgId = 98765;
     ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
 
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were properly initialized.
+    // Check that StateTrackers were initialized correctly.
     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1,
-              StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
 
     // Check that CountMetricProducer was initialized correctly.
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -116,58 +223,371 @@
     EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
     sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
     EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
     EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
 
     StateMap map = state.map();
     for (auto group : map.group()) {
         for (auto value : group.value()) {
-            EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value],
+            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
                       group.group_id());
         }
     }
+
+    /*
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10 (minutes)
+    |-----------------------------|-----------------------------|--
+      x   x     x       x    x   x      x         x         x       (syncStartEvents)
+     -----------------------------------------------------------SCREEN_OFF events
+       |                                                            (ScreenStateUnknownEvent = 0)
+             |                  |                                   (ScreenStateOffEvent = 1)
+                          |                                         (ScreenStateDozeEvent = 3)
+                                                |                   (ScreenStateDozeSuspendEvent = 4)
+     -----------------------------------------------------------SCREEN_ON events
+                   |                                       |        (ScreenStateOnEvent = 2)
+                      |                                             (ScreenStateVrEvent = 5)
+                                            |                       (ScreenStateOnSuspendEvent = 6)
+    */
+    // Initialize log events - first bucket.
+    int appUid = 123;
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+                                          bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
+                                          bucketStartTimeNs + 180 * NS_PER_SEC));  // 3:10
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
+                                          bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
+                                          bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
+    events.push_back(CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND,
+            bucketStartTimeNs + 430 * NS_PER_SEC));  // 7:20
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
+    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+                                          bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(4, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
 }
 
-TEST(CountMetricE2eTest, TestWithMultipleStates) {
-    // Initialize config
+/**
+ * Test a count metric that has one slice_by_state with a primary field.
+
+ * Once the CountMetricProducer is initialized, it should have one
+ * MetricStateLink stored. State querying using a non-empty primary key
+ * should also work as intended.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
+    // Initialize config.
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
-    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = syncStartMatcher;
+    auto appCrashMatcher =
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+    *config.add_atom_matcher() = appCrashMatcher;
+
+    auto state = CreateUidProcessState();
+    *config.add_state() = state;
+
+    // Create count metric that slices by uid process state.
+    int64_t metricId = 123456;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(metricId);
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+    countMetric->add_slice_by_state(state.id());
+    MetricStateLink* stateLink = countMetric->add_state_link();
+    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+    auto fieldsInWhat = stateLink->mutable_fields_in_what();
+    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
+    auto fieldsInState = stateLink->mutable_fields_in_state();
+    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+    // Check that StateTrackers were initialized correctly.
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+    // Check that CountMetricProducer was initialized correctly.
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+    /*
+    NOTE: "1" or "2" represents the uid associated with the state/app crash event
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10
+    |-----------------------------|-----------------------------|--
+      1   1     1       1    1   2      1         1          2      (AppCrashEvents)
+     -----------------------------------------------------------PROCESS STATE events
+             1                  2                                   (ProcessStateTopEvent = 1002)
+                          1                 1                       (ProcessStateForegroundServiceEvent = 1003)
+                                                2                   (ProcessStateImportantBackgroundEvent = 1006)
+        1          1                                       1        (ProcessStateImportantForegroundEvent = 1005)
+
+    Based on the diagram above, an AppCrashEvent querying for process state value would return:
+    - StateTracker::kStateUnknown
+    - Important foreground
+    - Top
+    - Important foreground
+    - Foreground service
+    - Top (both the app crash and state still have matching uid = 2)
+
+    - Foreground service
+    - Foreground service
+    - Important background
+    */
+    // Initialize log events - first bucket.
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+            bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+            bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
+    events.push_back(CreateUidProcessStateChangedEvent(
+            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+            bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
+    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+                                                 bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+            bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
+    events.push_back(CreateUidProcessStateChangedEvent(
+            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+            bucketStartTimeNs + 430 * NS_PER_SEC));  // 7:20
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
+    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+                                                 bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(3);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(4);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
+    // Initialize config.
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto appCrashMatcher =
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+    *config.add_atom_matcher() = appCrashMatcher;
 
     auto state1 = CreateScreenStateWithOnOffMap();
     *config.add_state() = state1;
     auto state2 = CreateUidProcessState();
     *config.add_state() = state2;
 
-    // Create count metric that slices by screen state with on/off map
+    // Create count metric that slices by screen state with on/off map and
+    // slices by uid process state.
     int64_t metricId = 123456;
     auto countMetric = config.add_count_metric();
     countMetric->set_id(metricId);
-    countMetric->set_what(syncStartMatcher.id());
-    countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     countMetric->add_slice_by_state(state1.id());
     countMetric->add_slice_by_state(state2.id());
+    MetricStateLink* stateLink = countMetric->add_state_link();
+    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+    auto fieldsInWhat = stateLink->mutable_fields_in_what();
+    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
+    auto fieldsInState = stateLink->mutable_fields_in_state();
+    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
 
-    // Initialize StatsLogProcessor
-    const int64_t baseTimeNs = 0;                                   // 0:00
-    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
     int uid = 12345;
     int64_t cfgId = 98765;
     ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
 
     // Check that StateTrackers were properly initialized.
     EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1,
-              StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         android::util::UID_PROCESS_STATE_CHANGED));
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
 
     // Check that CountMetricProducer was initialized correctly.
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -176,17 +596,205 @@
     EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
     sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
     EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), android::util::UID_PROCESS_STATE_CHANGED);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
     EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
 
     StateMap map = state1.map();
     for (auto group : map.group()) {
         for (auto value : group.value()) {
-            EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value],
+            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
                       group.group_id());
         }
     }
+
+    /*
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10 (minutes)
+    |-----------------------------|-----------------------------|--
+      1   1     1       1    1   2      1         1           2     (AppCrashEvents)
+     -----------------------------------------------------------SCREEN_OFF events
+       |                                                            (ScreenStateUnknownEvent = 0)
+             |                                  |                   (ScreenStateOffEvent = 1)
+                          |                                         (ScreenStateDozeEvent = 3)
+     -----------------------------------------------------------SCREEN_ON events
+                    |                                    |          (ScreenStateOnEvent = 2)
+                                            |                       (ScreenStateOnSuspendEvent = 6)
+     -----------------------------------------------------------PROCESS STATE events
+             1                  2                                   (ProcessStateTopEvent = 1002)
+                                          1                         (ProcessStateForegroundServiceEvent = 1003)
+                                               2                    (ProcessStateImportantBackgroundEvent = 1006)
+     1             1                                       1        (ProcessStateImportantForegroundEvent = 1005)
+
+     Based on the diagram above, Screen State / Process State pairs for each
+     AppCrashEvent are:
+     - StateTracker::kStateUnknown / important foreground
+     - off / important foreground
+     - off / Top
+     - on / important foreground
+     - off / important foreground
+     - off / top
+
+     - off / important foreground
+     - off / foreground service
+     - on / important background
+
+    */
+    // Initialize log events - first bucket.
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 5 * NS_PER_SEC));  // 0:15
+    events.push_back(
+            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+                                          bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+            bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 160 * NS_PER_SEC));  // 2:50
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
+                                          bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
+    events.push_back(CreateUidProcessStateChangedEvent(
+            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+            bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
+    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+                                                 bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+            bucketStartTimeNs + 380 * NS_PER_SEC));  // 6:30
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
+                                          bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
+    events.push_back(CreateUidProcessStateChangedEvent(
+            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+            bucketStartTimeNs + 420 * NS_PER_SEC));  // 7:10
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
+    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+                                                 bucketStartTimeNs + 450 * NS_PER_SEC));  // 7:40
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 520 * NS_PER_SEC));  // 8:50
+    events.push_back(CreateUidProcessStateChangedEvent(
+            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+            bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
+    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+                                                 bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1, data.slice_by_state(0).value());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(3);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(4);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(5);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
index 7b9c0d6..108df04 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.cpp
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
@@ -26,10 +26,23 @@
     return dimension;
 }
 
+HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value) {
+    HashableDimensionKey dimension;
+    int pos[] = {key, 0, 0};
+    dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value)));
+
+    return dimension;
+}
+
 MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, string value) {
     return MetricDimensionKey(getMockedDimensionKey(tagId, key, value), DEFAULT_DIMENSION_KEY);
 }
 
+MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value) {
+    return MetricDimensionKey(DEFAULT_DIMENSION_KEY,
+                              getMockedDimensionKeyLongValue(tagId, key, value));
+}
+
 void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) {
     matcher->set_field(tagId);
 }
@@ -41,4 +54,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 329e39f..09c4d9e 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -47,6 +47,9 @@
 HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
 MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
 
+HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value);
+MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value);
+
 // Utils to build FieldMatcher proto for simple one-depth atoms.
 void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher);
 void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 8d38000..4208fef 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -50,6 +50,12 @@
     }
 };
 
+int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& queryKey) {
+    FieldValue output;
+    mgr.getStateValue(atomId, queryKey, &output);
+    return output.mValue.int_value;
+}
+
 // START: build event functions.
 // State with no primary fields - ScreenStateChanged
 std::shared_ptr<LogEvent> buildScreenEvent(int state) {
@@ -240,7 +246,7 @@
 
     // check StateTracker was updated by querying for state
     HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, queryKey));
+    EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey));
 }
 
 /**
@@ -265,7 +271,7 @@
     // check StateTracker was updated by querying for state
     HashableDimensionKey queryKey;
     getUidProcessKey(1000 /* uid */, &queryKey);
-    EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey));
+    EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey));
 }
 
 /**
@@ -290,7 +296,7 @@
     // check StateTracker was updated by querying for state
     HashableDimensionKey queryKey;
     getOverlayKey(1000 /* uid */, "package1", &queryKey);
-    EXPECT_EQ(1, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey));
+    EXPECT_EQ(1, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey));
 }
 
 /**
@@ -353,25 +359,25 @@
     // Query for UidProcessState of uid 1001
     HashableDimensionKey queryKey1;
     getUidProcessKey(1001, &queryKey1);
-    EXPECT_EQ(1003, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+    EXPECT_EQ(1003, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
 
     // Query for UidProcessState of uid 1004 - not in state map
     HashableDimensionKey queryKey2;
     getUidProcessKey(1004, &queryKey2);
-    EXPECT_EQ(-1, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED,
-                                    queryKey2));  // default state
+    EXPECT_EQ(-1, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED,
+                              queryKey2));  // default state
 
     // Query for UidProcessState of uid 1001 - after change in state
     mgr.onLogEvent(*event4);
-    EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+    EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
 
     // Query for ScreenState
-    EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+    EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
 
     // Query for OverlayState of uid 1000, package name "package2"
     HashableDimensionKey queryKey3;
     getOverlayKey(1000, "package2", &queryKey3);
-    EXPECT_EQ(2, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey3));
+    EXPECT_EQ(2, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3));
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 38c22ab..d154b1b 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -254,28 +254,28 @@
 State CreateScreenState() {
     State state;
     state.set_id(StringToId("ScreenState"));
-    state.set_atom_id(29);
+    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
     return state;
 }
 
 State CreateUidProcessState() {
     State state;
     state.set_id(StringToId("UidProcessState"));
-    state.set_atom_id(27);
+    state.set_atom_id(android::util::UID_PROCESS_STATE_CHANGED);
     return state;
 }
 
 State CreateOverlayState() {
     State state;
     state.set_id(StringToId("OverlayState"));
-    state.set_atom_id(59);
+    state.set_atom_id(android::util::OVERLAY_STATE_CHANGED);
     return state;
 }
 
 State CreateScreenStateWithOnOffMap() {
     State state;
     state.set_id(StringToId("ScreenStateOnOff"));
-    state.set_atom_id(29);
+    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
 
     auto map = CreateScreenStateOnOffMap();
     *state.mutable_map() = map;
@@ -286,7 +286,7 @@
 State CreateScreenStateWithInDozeMap() {
     State state;
     state.set_id(StringToId("ScreenStateInDoze"));
-    state.set_atom_id(29);
+    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
 
     auto map = CreateScreenStateInDozeMap();
     *state.mutable_map() = map;
@@ -533,6 +533,15 @@
         uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
 }
 
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) {
+    auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs);
+    event->write(uid);
+    event->write("eventType");
+    event->write("processName");
+    event->init();
+    return event;
+}
+
 std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
     int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
     auto logEvent = std::make_unique<LogEvent>(
@@ -544,6 +553,15 @@
     return logEvent;
 }
 
+std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
+        int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) {
+    auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs);
+    event->write(uid);
+    event->write(state);
+    event->init();
+    return event;
+}
+
 sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
                                               const StatsdConfig& config, const ConfigKey& key) {
     sp<UidMap> uidMap = new UidMap();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index c026105..e1e134b 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -192,6 +192,9 @@
 std::unique_ptr<LogEvent> CreateAppCrashEvent(
     const int uid, uint64_t timestampNs);
 
+// Create log event for an app crash.
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs);
+
 // Create log event for acquiring wakelock.
 std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
         const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
@@ -206,6 +209,10 @@
 std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
     int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
 
+// Create log event for uid process state change.
+std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
+        int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs);
+
 // Helper function to create an AttributionNodeInternal proto.
 AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
 
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index b540175..8b62e2f 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -76,9 +76,9 @@
             GESTURE_SWIPE_RIGHT_AND_DOWN
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface GestureType {}
+    public @interface GestureId {}
 
-    @GestureType
+    @GestureId
     private final int mGestureId;
     private final int mDisplayId;
 
@@ -110,7 +110,7 @@
      * @return the performed gesture id.
      *
      */
-    @GestureType public int getGestureId() {
+    @GestureId public int getGestureId() {
         return mGestureId;
     }
 
diff --git a/core/java/android/annotation/UserHandleAware.java b/core/java/android/annotation/UserHandleAware.java
new file mode 100644
index 0000000..7d3d20b
--- /dev/null
+++ b/core/java/android/annotation/UserHandleAware.java
@@ -0,0 +1,49 @@
+/*
+ * 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates an API that uses {@code context.getUser} or {@code context.getUserId}
+ * to operate across users (as the user associated with the context)
+ * <p>
+ * To create a {@link android.content.Context} associated with a different user,
+ *  use {@link android.content.Context#createContextAsUser} or
+ *  {@link android.content.Context#createPackageContextAsUser}
+ * <p>
+ * Example:
+ * <pre>{@code
+ * {@literal @}UserHandleAware
+ * public abstract PackageInfo getPackageInfo({@literal @}NonNull String packageName,
+ *      {@literal @}PackageInfoFlags int flags) throws NameNotFoundException;
+ * }</pre>
+ *
+ * @memberDoc This method uses {@linkplain android.content.Context#getUser}
+ *            or {@linkplain android.content.Context#getUserId} to execute across users.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({TYPE, METHOD, CONSTRUCTOR, PACKAGE})
+public @interface UserHandleAware {
+}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2931f33..fce7449 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3204,6 +3204,14 @@
     }
 
     /**
+     * Sets the {@link BubbleMetadata} for this notification.
+     * @hide
+     */
+    public void setBubbleMetadata(BubbleMetadata data) {
+        mBubbleMetadata = data;
+    }
+
+    /**
      * Returns whether the platform is allowed (by the app developer) to generate contextual actions
      * for this notification.
      */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ad671df..9eff4b0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3499,24 +3499,25 @@
      * Returns how complex the current user's screen lock is.
      *
      * <p>Note that when called from a profile which uses an unified challenge with its parent, the
-     * screen lock complexity of the parent will be returned. However, this API does not support
-     * explicitly querying the parent profile screen lock complexity via {@link
-     * #getParentProfileInstance}.
+     * screen lock complexity of the parent will be returned.
+     *
+     * <p>This method can be called on the {@link DevicePolicyManager} instance
+     * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+     * restrictions on the parent profile.
      *
      * @throws IllegalStateException if the user is not unlocked.
-     * @throws SecurityException if the calling application does not have the permission
-     *                           {@link permission#REQUEST_PASSWORD_COMPLEXITY}
+     * @throws SecurityException     if the calling application does not have the permission
+     *                               {@link permission#REQUEST_PASSWORD_COMPLEXITY}
      */
     @PasswordComplexity
     @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY)
     public int getPasswordComplexity() {
-        throwIfParentInstance("getPasswordComplexity");
         if (mService == null) {
             return PASSWORD_COMPLEXITY_NONE;
         }
 
         try {
-            return mService.getPasswordComplexity();
+            return mService.getPasswordComplexity(mParentInstance);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -9254,6 +9255,7 @@
      * <li>{@link #setPasswordExpirationTimeout}</li>
      * <li>{@link #getPasswordExpiration}</li>
      * <li>{@link #getPasswordMaximumLength}</li>
+     * <li>{@link #getPasswordComplexity}</li>
      * <li>{@link #isActivePasswordSufficient}</li>
      * <li>{@link #getCurrentFailedPasswordAttempts}</li>
      * <li>{@link #getMaximumFailedPasswordsForWipe}</li>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6b50522..4894751 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -84,7 +84,7 @@
 
     boolean isActivePasswordSufficient(int userHandle, boolean parent);
     boolean isProfileActivePasswordSufficientForParent(int userHandle);
-    int getPasswordComplexity();
+    int getPasswordComplexity(boolean parent);
     boolean isUsingUnifiedPassword(in ComponentName admin);
     int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
     int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 95d66bb..39cb323 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -304,7 +304,8 @@
     }
 
     /**
-     * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+     * Sets the
+     * <a class="external" href="https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html">Next
      * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
      *
      * <p>For servers this is the sequence of protocols to advertise as
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index fda1539..a856975 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -933,8 +933,7 @@
 
         int result = -1;
         try {
-            result = handleShellCommand(new ParcelFileDescriptor(in),
-                    new ParcelFileDescriptor(out), new ParcelFileDescriptor(err), args);
+            result = handleShellCommand(in, out, err, args);
         } finally {
             resultReceiver.send(result, null);
         }
@@ -955,10 +954,9 @@
      * @hide
      */
     // @SystemApi TODO Make it a system API.
-    protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
-            @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
-            @NonNull String[] args) {
-        FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor());
+    protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            @NonNull FileDescriptor err, @NonNull String[] args) {
+        FileOutputStream ferr = new FileOutputStream(err);
         PrintWriter pw = new FastPrintWriter(ferr);
         pw.println("No shell command implementation.");
         pw.flush();
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
new file mode 100644
index 0000000..1c832ca
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -0,0 +1,96 @@
+/*
+ * 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 IIncrementalService {
+    /**
+     * 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);
+
+    /**
+     * 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 a storage.
+     * Both source and destination are specified by relative paths under storage.
+     */
+    int makeLink(int storageId, in @utf8InCpp String sourcePathUnderStorage, 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);
+
+    /**
+     * Returns the list of file paths under a storage.
+     */
+    @utf8InCpp String[] getFileList(int storageId);
+
+    /**
+     * Starts loading data for a storage.
+     */
+    boolean startLoading(int storageId);
+}
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
new file mode 100644
index 0000000..12740ea
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.service.incremental.IIncrementalDataLoaderStatusListener;
+
+/**
+ * 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 IIncrementalDataLoaderStatusListener 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/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
new file mode 100644
index 0000000..50c28f0
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.NamedParcelFileDescriptor;
+
+/**
+ * Class for holding data loader configuration parameters.
+ * @hide
+ */
+parcelable IncrementalDataLoaderParamsParcel {
+    @utf8InCpp String staticUri;
+    @utf8InCpp String packageName;
+    NamedParcelFileDescriptor[] dynamicArgs;
+}
diff --git a/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
new file mode 100644
index 0000000..0ae353d
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * Wraps two file descriptors that Incremental Service uses to communicate
+ * with Incremental FileSystem.
+ * @hide
+ */
+parcelable IncrementalFileSystemControlParcel {
+    @nullable ParcelFileDescriptor cmd;
+    @nullable ParcelFileDescriptor log;
+}
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
new file mode 100644
index 0000000..038ced1
--- /dev/null
+++ b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.ParcelFileDescriptor;
+
+/**
+ * A named ParcelFileDescriptor.
+ * @hide
+ */
+parcelable NamedParcelFileDescriptor {
+    @utf8InCpp String name;
+    ParcelFileDescriptor fd;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2d8af83..ac7a0a8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -779,7 +779,12 @@
     /** {@hide} */
     public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
         if (emulatedVol != null) {
-            return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
+            String id = emulatedVol.getId();
+            int idx = id.indexOf(";");
+            if (idx != -1) {
+                id = id.substring(0, idx);
+            }
+            return findVolumeById(id.replace("emulated", "private"));
         } else {
             return null;
         }
@@ -789,7 +794,8 @@
     @UnsupportedAppUsage
     public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
         if (privateVol != null) {
-            return findVolumeById(privateVol.getId().replace("private", "emulated"));
+            return findVolumeById(privateVol.getId().replace("private", "emulated") + ";"
+                    + mContext.getUserId());
         } else {
             return null;
         }
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 7699a05..d6ec52f 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -266,7 +266,7 @@
 
     @UnsupportedAppUsage
     public @Nullable String getDescription() {
-        if (ID_PRIVATE_INTERNAL.equals(id) || ID_EMULATED_INTERNAL.equals(id)) {
+        if (ID_PRIVATE_INTERNAL.equals(id) || id.startsWith(ID_EMULATED_INTERNAL + ";")) {
             return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
         } else if (!TextUtils.isEmpty(fsLabel)) {
             return fsLabel;
@@ -301,13 +301,20 @@
     }
 
     public boolean isVisibleForUser(int userId) {
-        if ((type == TYPE_PUBLIC || type == TYPE_STUB) && mountUserId == userId) {
+        if ((type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED)
+                && mountUserId == userId) {
             return isVisible();
-        } else if (type == TYPE_EMULATED) {
-            return isVisible();
-        } else {
-            return false;
         }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this volume is the primary emulated volume for {@code userId},
+     * {@code false} otherwise.
+     */
+    @UnsupportedAppUsage
+    public boolean isPrimaryEmulatedForUser(int userId) {
+        return id.equals(ID_EMULATED_INTERNAL + ";" + userId);
     }
 
     public boolean isVisibleForRead(int userId) {
@@ -390,7 +397,7 @@
                 derivedFsUuid = privateVol.fsUuid;
             }
 
-            if (ID_EMULATED_INTERNAL.equals(id)) {
+            if (isPrimaryEmulatedForUser(userId)) {
                 removable = false;
             } else {
                 removable = true;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fbc3fee..4773d98 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1262,6 +1262,33 @@
             = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
 
     /**
+     * Activity Action: Show notification listener permission settings page for app.
+     * <p>
+     * Users can grant and deny access to notifications for a {@link ComponentName} from here.
+     * See
+     * {@link android.app.NotificationManager#isNotificationListenerAccessGranted(ComponentName)}
+     * for more details.
+     * <p>
+     * Input: The extra {@link #EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME} containing the name
+     * of the component to grant or revoke notification listener access to.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS =
+            "android.settings.NOTIFICATION_LISTENER_DETAIL_SETTINGS";
+
+    /**
+     * Activity Extra: What component name to show the notification listener permission
+     * page for.
+     * <p>
+     * A string extra containing a {@link ComponentName}. This must be passed as an extra field to
+     * {@link #ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS}.
+     */
+    public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME =
+            "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
+
+    /**
      * Activity Action: Show Do Not Disturb access settings.
      * <p>
      * Users can grant and deny access to Do Not Disturb configuration from here. Managed
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
new file mode 100644
index 0000000..723fc59
--- /dev/null
+++ b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.service.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.service.incremental.IIncrementalDataLoaderStatusListener;
+
+/** @hide */
+oneway interface IIncrementalDataLoaderService {
+   void createDataLoader(in int storageId,
+                 in IncrementalFileSystemControlParcel control,
+                 in IncrementalDataLoaderParamsParcel params,
+                 in IIncrementalDataLoaderStatusListener listener,
+                 in boolean start);
+   void startDataLoader(in int storageId);
+   void stopDataLoader(in int storageId);
+   void destroyDataLoader(in int storageId);
+   void onFileCreated(in int storageId, in long inode, in byte[] metadata);
+}
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
new file mode 100644
index 0000000..f04242d
--- /dev/null
+++ b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.service.incremental;
+
+/**
+ * Callbacks from DataLoaderService to IncrementalService to report data loader status.
+ * @hide
+ */
+oneway interface IIncrementalDataLoaderStatusListener {
+    /** Data loader status */
+    const int DATA_LOADER_READY = 0;
+    const int DATA_LOADER_NOT_READY = 1;
+    const int DATA_LOADER_RUNNING = 2;
+    const int DATA_LOADER_STOPPED = 3;
+    const int DATA_LOADER_SLOW_CONNECTION = 4;
+    const int DATA_LOADER_NO_CONNECTION = 5;
+    const int DATA_LOADER_CONNECTION_OK = 6;
+
+    /** Data loader status callback */
+    void onStatusChanged(in int storageId, in int status);
+}
+
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e784ad3..d5c6766 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -176,14 +176,10 @@
         int mCurWindowPrivateFlags = mWindowPrivateFlags;
         final Rect mVisibleInsets = new Rect();
         final Rect mWinFrame = new Rect();
-        final Rect mOverscanInsets = new Rect();
         final Rect mContentInsets = new Rect();
         final Rect mStableInsets = new Rect();
-        final Rect mOutsets = new Rect();
-        final Rect mDispatchedOverscanInsets = new Rect();
         final Rect mDispatchedContentInsets = new Rect();
         final Rect mDispatchedStableInsets = new Rect();
-        final Rect mDispatchedOutsets = new Rect();
         final Rect mFinalSystemInsets = new Rect();
         final Rect mFinalStableInsets = new Rect();
         final Rect mBackdropFrame = new Rect();
@@ -317,13 +313,13 @@
 
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                    Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+            public void resized(Rect frame, Rect contentInsets,
+                    Rect visibleInsets, Rect stableInsets, boolean reportDraw,
                     MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
                     boolean alwaysConsumeSystemBars, int displayId,
                     DisplayCutout.ParcelableWrapper displayCutout) {
-                Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
-                        reportDraw ? 1 : 0, outsets);
+                Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+                        reportDraw ? 1 : 0);
                 mCaller.sendMessage(msg);
             }
 
@@ -822,7 +818,7 @@
 
                         if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
                                 mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
-                                mOutsets, mDisplayCutout, inputChannel,
+                                mDisplayCutout, inputChannel,
                                 mInsetsState) < 0) {
                             Log.w(TAG, "Failed to add window while updating wallpaper surface.");
                             return;
@@ -838,17 +834,13 @@
 
                     if (!fixedSize) {
                         mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding);
-                        mLayout.surfaceInsets.left += mOutsets.left;
-                        mLayout.surfaceInsets.top += mOutsets.top;
-                        mLayout.surfaceInsets.right += mOutsets.right;
-                        mLayout.surfaceInsets.bottom += mOutsets.bottom;
                     } else {
                         mLayout.surfaceInsets.set(0, 0, 0, 0);
                     }
                     final int relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
-                            View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
+                            View.VISIBLE, 0, -1, mWinFrame, mContentInsets,
+                            mVisibleInsets, mStableInsets, mBackdropFrame,
                             mDisplayCutout, mMergedConfiguration, mSurfaceControl,
                             mInsetsState);
                     if (mSurfaceControl.isValid()) {
@@ -864,12 +856,8 @@
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
-                        w += padding.left + padding.right + mOutsets.left + mOutsets.right;
-                        h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom;
-                        mOverscanInsets.left += padding.left;
-                        mOverscanInsets.top += padding.top;
-                        mOverscanInsets.right += padding.right;
-                        mOverscanInsets.bottom += padding.bottom;
+                        w += padding.left + padding.right;
+                        h += padding.top + padding.bottom;
                         mContentInsets.left += padding.left;
                         mContentInsets.top += padding.top;
                         mContentInsets.right += padding.right;
@@ -898,10 +886,8 @@
                         Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight);
                     }
 
-                    insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets);
                     insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
                     insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
-                    insetsChanged |= !mDispatchedOutsets.equals(mOutsets);
                     insetsChanged |= !mDispatchedDisplayCutout.equals(mDisplayCutout.get());
 
                     mSurfaceHolder.setSurfaceFrameSize(w, h);
@@ -961,16 +947,9 @@
                         }
 
                         if (insetsChanged) {
-                            mDispatchedOverscanInsets.set(mOverscanInsets);
-                            mDispatchedOverscanInsets.left += mOutsets.left;
-                            mDispatchedOverscanInsets.top += mOutsets.top;
-                            mDispatchedOverscanInsets.right += mOutsets.right;
-                            mDispatchedOverscanInsets.bottom += mOutsets.bottom;
                             mDispatchedContentInsets.set(mContentInsets);
                             mDispatchedStableInsets.set(mStableInsets);
-                            mDispatchedOutsets.set(mOutsets);
                             mDispatchedDisplayCutout = mDisplayCutout.get();
-                            mFinalSystemInsets.set(mDispatchedOverscanInsets);
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                     mFinalStableInsets,
@@ -1457,7 +1436,6 @@
                 } break;
                 case MSG_WINDOW_RESIZED: {
                     final boolean reportDraw = message.arg1 != 0;
-                    mEngine.mOutsets.set((Rect) message.obj);
                     mEngine.updateSurface(true, false, reportDraw);
                     mEngine.doOffsetsChanged(true);
                 } break;
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index c40c123..451a669 100755
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -23,9 +23,8 @@
 /**
  * A structure describing general information about a display, such as its
  * size, density, and font scaling.
- * <p>To access the DisplayMetrics members, initialize an object like this:</p>
- * <pre> DisplayMetrics metrics = new DisplayMetrics();
- * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
+ * <p>To access the DisplayMetrics members, retrieve display metrics like this:</p>
+ * <pre>context.getResources().getDisplayMetrics();</pre>
  */
 public class DisplayMetrics {
     /**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index af1a51f..12a55c7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -56,6 +56,7 @@
         DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
         DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
         DEFAULT_FLAGS.put("settings_work_profile", "false");
+        DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
     }
 
     /**
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index a21f9e0..d6ffd38 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -63,7 +63,7 @@
      * Returns a new StatsEvent.Builder for building StatsEvent object.
      **/
     @NonNull
-    public StatsEvent.Builder newBuilder() {
+    public static StatsEvent.Builder newBuilder() {
         return new StatsEvent.Builder(Buffer.obtain());
     }
 
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b3d98b8..03e68b0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -749,20 +749,6 @@
     }
 
     /**
-     * @hide
-     * Return a rectangle defining the insets of the overscan region of the display.
-     * Each field of the rectangle is the number of pixels the overscan area extends
-     * into the display on that side.
-     */
-    public void getOverscanInsets(Rect outRect) {
-        synchronized (this) {
-            updateDisplayInfoLocked();
-            outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
-                    mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
-        }
-    }
-
-    /**
      * Returns the rotation of the screen from its "natural" orientation.
      * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
      * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 7e22dd9..38baccb 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -136,30 +136,6 @@
     public int logicalHeight;
 
     /**
-     * @hide
-     * Number of overscan pixels on the left side of the display.
-     */
-    public int overscanLeft;
-
-    /**
-     * @hide
-     * Number of overscan pixels on the top side of the display.
-     */
-    public int overscanTop;
-
-    /**
-     * @hide
-     * Number of overscan pixels on the right side of the display.
-     */
-    public int overscanRight;
-
-    /**
-     * @hide
-     * Number of overscan pixels on the bottom side of the display.
-     */
-    public int overscanBottom;
-
-    /**
      * The {@link DisplayCutout} if present, otherwise {@code null}.
      *
      * @hide
@@ -322,10 +298,6 @@
                 && largestNominalAppHeight == other.largestNominalAppHeight
                 && logicalWidth == other.logicalWidth
                 && logicalHeight == other.logicalHeight
-                && overscanLeft == other.overscanLeft
-                && overscanTop == other.overscanTop
-                && overscanRight == other.overscanRight
-                && overscanBottom == other.overscanBottom
                 && Objects.equals(displayCutout, other.displayCutout)
                 && rotation == other.rotation
                 && modeId == other.modeId
@@ -365,10 +337,6 @@
         largestNominalAppHeight = other.largestNominalAppHeight;
         logicalWidth = other.logicalWidth;
         logicalHeight = other.logicalHeight;
-        overscanLeft = other.overscanLeft;
-        overscanTop = other.overscanTop;
-        overscanRight = other.overscanRight;
-        overscanBottom = other.overscanBottom;
         displayCutout = other.displayCutout;
         rotation = other.rotation;
         modeId = other.modeId;
@@ -404,10 +372,6 @@
         largestNominalAppHeight = source.readInt();
         logicalWidth = source.readInt();
         logicalHeight = source.readInt();
-        overscanLeft = source.readInt();
-        overscanTop = source.readInt();
-        overscanRight = source.readInt();
-        overscanBottom = source.readInt();
         displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
         rotation = source.readInt();
         modeId = source.readInt();
@@ -452,10 +416,6 @@
         dest.writeInt(largestNominalAppHeight);
         dest.writeInt(logicalWidth);
         dest.writeInt(logicalHeight);
-        dest.writeInt(overscanLeft);
-        dest.writeInt(overscanTop);
-        dest.writeInt(overscanRight);
-        dest.writeInt(overscanBottom);
         DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
         dest.writeInt(rotation);
         dest.writeInt(modeId);
@@ -632,17 +592,6 @@
         sb.append(logicalWidth);
         sb.append(" x ");
         sb.append(logicalHeight);
-        if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
-            sb.append(", overscan (");
-            sb.append(overscanLeft);
-            sb.append(",");
-            sb.append(overscanTop);
-            sb.append(",");
-            sb.append(overscanRight);
-            sb.append(",");
-            sb.append(overscanBottom);
-            sb.append(")");
-        }
         sb.append(", largest app ");
         sb.append(largestNominalAppWidth);
         sb.append(" x ");
diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl
new file mode 100644
index 0000000..725cd6f
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.view;
+
+/**
+ * Interface to listen for changes to display window-containers.
+ *
+ * This differs from DisplayManager's DisplayListener:
+ *  - onDisplayAdded is always called after the display is actually added to the WM hierarchy.
+ *    This corresponds to the DisplayContent and not the raw Dislay from DisplayManager.
+ *
+ * @hide
+ */
+oneway interface IDisplayWindowListener {
+
+    /**
+     * Called when a display is added to the WM hierarchy.
+     */
+    void onDisplayAdded(int displayId);
+
+    /**
+     * Called when a display is removed from the hierarchy.
+     */
+    void onDisplayRemoved(int displayId);
+
+}
diff --git a/core/java/android/view/IDisplayWindowRotationCallback.aidl b/core/java/android/view/IDisplayWindowRotationCallback.aidl
new file mode 100644
index 0000000..79a15ad
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowRotationCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.view;
+
+import android.view.WindowContainerTransaction;
+
+/**
+ * Interface to be invoked by the controller when it has finished preparing for a display rotation.
+ *
+ * @see IDisplayWindowRotationController
+ * @hide
+ */
+interface IDisplayWindowRotationCallback {
+    void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
+}
diff --git a/core/java/android/view/IDisplayWindowRotationController.aidl b/core/java/android/view/IDisplayWindowRotationController.aidl
new file mode 100644
index 0000000..c1c7464
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowRotationController.aidl
@@ -0,0 +1,52 @@
+/**
+ * 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.view;
+
+import android.view.IDisplayWindowRotationCallback;
+
+/**
+ * Singular controller of a "remote" display rotation. When a display rotation is started, WM
+ * freezes the screen. It will then call into this controller and wait for a response via the
+ * callback.
+ *
+ * This needs to provide configuration changes because those changes need to be applied in sync
+ * with the actual display rotation to prevent relayouts with mismatched information.
+ *
+ * The flow is like this:
+ *  1. DisplayContent/Rotation freezes the screen
+ *  2. This controller is notified of a rotation and provided a callback.
+ *  3. This controller is responsible for collecting a set of configuration changes to go along with
+ *     the rotation.
+ *  4. The callback is fired which tells DisplayContent/Rotation to apply the provided configuration
+ *     changes and continue the rotation.
+ *
+ * @hide
+ */
+oneway interface IDisplayWindowRotationController {
+
+    /**
+     * Called when WM needs to know how to update tasks in response to a display rotation.
+     * If this isn't called, a timeout will continue the rotation in WM.
+     *
+     * @param displayId the display that is rotating.
+     * @param fromRotation the rotation the display is rotating from.
+     * @param toRotation the rotation the display is rotating to.
+     * @param callback A callback to be called when this has calculated updated configs.
+     */
+    void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+            in IDisplayWindowRotationCallback callback);
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8bf99ec..37b685a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -51,8 +51,8 @@
      */
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
-    void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
-            in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
+    void resized(in Rect frame, in Rect contentInsets,
+            in Rect visibleInsets, in Rect stableInsets, boolean reportDraw,
             in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
             boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
             in DisplayCutout.ParcelableWrapper displayCutout);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7f717a7..258b1ae 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,7 +35,9 @@
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDockedStackListener;
+import android.view.IDisplayWindowListener;
 import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowRotationController;
 import android.view.IOnKeyguardExitResult;
 import android.view.IPinnedStackListener;
 import android.view.RemoteAnimationAdapter;
@@ -88,8 +90,6 @@
     void clearForcedDisplayDensityForUser(int displayId, int userId);
     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
 
-    void setOverscan(int displayId, int left, int top, int right, int bottom);
-
     // These can only be called when holding the MANAGE_APP_TOKENS permission.
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type, int displayId);
@@ -97,6 +97,13 @@
     void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
 
     /**
+     * Sets a singular remote controller of display rotations. There can only be one. The
+     * controller is called after the display has "frozen" for a rotation and display rotation will
+     * only continue once the controller has finished calculating associated configurations.
+     */
+    void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
+
+    /**
      * 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.
@@ -476,6 +483,16 @@
     void unregisterDisplayFoldListener(IDisplayFoldListener listener);
 
     /**
+     * Registers an IDisplayContainerListener
+     */
+    void registerDisplayWindowListener(IDisplayWindowListener listener);
+
+    /**
+     * Unregisters an IDisplayContainerListener.
+     */
+    void unregisterDisplayWindowListener(IDisplayWindowListener listener);
+
+    /**
      * Starts a window trace.
      */
     void startWindowTrace();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index eaf6fca..0489e14 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -43,7 +43,7 @@
 interface IWindowSession {
     int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             in int viewVisibility, in int layerStackId, out Rect outFrame,
-            out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets,
+            out Rect outContentInsets, out Rect outStableInsets,
             out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
             out InsetsState insetsState);
     int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
@@ -70,9 +70,6 @@
      * @param frameNumber A frame number in which changes requested in this layout will be rendered.
      * @param outFrame Rect in which is placed the new position/size on
      * screen.
-     * @param outOverscanInsets Rect in which is placed the offsets from
-     * <var>outFrame</var> in which the content of the window are inside
-     * of the display's overlay region.
      * @param outContentInsets Rect in which is placed the offsets from
      * <var>outFrame</var> in which the content of the window should be
      * placed.  This can be used to modify the window layout to ensure its
@@ -99,9 +96,9 @@
      */
     int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
-            int flags, long frameNumber, out Rect outFrame, out Rect outOverscanInsets,
+            int flags, long frameNumber, out Rect outFrame,
             out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
-            out Rect outOutsets, out Rect outBackdropFrame,
+            out Rect outBackdropFrame,
             out DisplayCutout.ParcelableWrapper displayCutout,
             out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
             out InsetsState insetsState);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8dd475e..b815c64 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -196,6 +196,8 @@
             float brightness);
     private static native long nativeReadTransactionFromParcel(Parcel in);
     private static native void nativeWriteTransactionToParcel(long nativeObject, Parcel out);
+    private static native void nativeSetShadowRadius(long transactionObj, long nativeObject,
+            float shadowRadius);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -2545,6 +2547,29 @@
             return this;
         }
 
+         /**
+          * Draws shadows of length {@code shadowRadius} around the surface {@link SurfaceControl}.
+          * If the length is 0.0f then the shadows will not be drawn.
+          *
+          * Shadows are drawn around the screen bounds, these are the post transformed cropped
+          * bounds. They can draw over their parent bounds and will be occluded by layers with a
+          * higher z-order. The shadows will respect the surface's corner radius if the
+          * rounded corner bounds (transformed source bounds) are within the screen bounds.
+          *
+          * A shadow will only be drawn on buffer and color layers. If the radius is applied on a
+          * container layer, it will be passed down the hierarchy to be applied on buffer and color
+          * layers but not its children. A scenario where this is useful is when SystemUI animates
+          * a task by controlling a leash to it, can draw a shadow around the app surface by
+          * setting a shadow on the leash. This is similar to how rounded corners are set.
+          *
+          * @hide
+          */
+        public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
+            sc.checkNotReleased();
+            nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius);
+            return this;
+        }
+
         /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fe06a70..3920271 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11287,16 +11287,14 @@
     public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
         if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
                 || mAttachInfo == null
-                || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
-                && !mAttachInfo.mOverscanRequested)) {
+                || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0)) {
             outLocalInsets.set(in.getSystemWindowInsetsAsRect());
             return in.consumeSystemWindowInsets().inset(outLocalInsets);
         } else {
             // The application wants to take care of fitting system window for
-            // the content...  however we still need to take care of any overscan here.
-            final Rect overscan = mAttachInfo.mOverscanInsets;
-            outLocalInsets.set(overscan);
-            return in.inset(outLocalInsets);
+            // the content.
+            outLocalInsets.setEmpty();
+            return in;
         }
     }
 
@@ -11376,19 +11374,6 @@
     }
 
     /**
-     * Returns the outsets, which areas of the device that aren't a surface, but we would like to
-     * treat them as such.
-     * @hide
-     */
-    public void getOutsets(Rect outOutsetRect) {
-        if (mAttachInfo != null) {
-            outOutsetRect.set(mAttachInfo.mOutsets);
-        } else {
-            outOutsetRect.setEmpty();
-        }
-    }
-
-    /**
      * Returns the visibility status for this view.
      *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -28445,13 +28430,6 @@
 
         /**
          * For windows that are full-screen but using insets to layout inside
-         * of the screen areas, these are the current insets to appear inside
-         * the overscan area of the display.
-         */
-        final Rect mOverscanInsets = new Rect();
-
-        /**
-         * For windows that are full-screen but using insets to layout inside
          * of the screen decorations, these are the current insets for the
          * content of the window.
          */
@@ -28478,12 +28456,6 @@
                 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
 
         /**
-         * For windows that include areas that are not covered by real surface these are the outsets
-         * for real surface.
-         */
-        final Rect mOutsets = new Rect();
-
-        /**
          * In multi-window we force show the system bars. Because we don't want that the surface
          * size changes in this mode, we instead have a flag whether the system bars sizes should
          * always be consumed, so the app is treated like there are no virtual system bars at all.
@@ -28592,12 +28564,6 @@
         boolean mHasSystemUiListeners;
 
         /**
-         * Set if the window has requested to extend into the overscan region
-         * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN.
-         */
-        boolean mOverscanRequested;
-
-        /**
          * Set if the visibility of any views has changed.
          */
         @UnsupportedAppUsage
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 97adaf5..8ee7a0e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -219,10 +219,6 @@
      */
     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
 
-    // properties used by emulator to determine display shape
-    public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
-            "ro.emu.win_outset_bottom_px";
-
     /**
      * Maximum time we allow the user to roll the trackball enough to generate
      * a key event, before resetting the counters.
@@ -447,7 +443,6 @@
     boolean mIsDrawing;
     int mLastSystemUiVisibility;
     int mClientWindowLayoutFlags;
-    boolean mLastOverscanRequested;
 
     // Pool of queued input events.
     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
@@ -507,11 +502,9 @@
     // These are accessed by multiple threads.
     final Rect mWinFrame; // frame given by window manager.
 
-    final Rect mPendingOverscanInsets = new Rect();
     final Rect mPendingVisibleInsets = new Rect();
     final Rect mPendingStableInsets = new Rect();
     final Rect mPendingContentInsets = new Rect();
-    final Rect mPendingOutsets = new Rect();
     final Rect mPendingBackDropFrame = new Rect();
     final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
             new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
@@ -900,7 +893,7 @@
                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                             getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
-                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, inputChannel,
+                            mAttachInfo.mDisplayCutout, inputChannel,
                             mTempInsets);
                     setFrame(mTmpFrame);
                 } catch (RemoteException e) {
@@ -921,7 +914,6 @@
                 if (mTranslator != null) {
                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
                 }
-                mPendingOverscanInsets.set(0, 0, 0, 0);
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
                 mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
@@ -1967,12 +1959,6 @@
                 stableInsets = mPendingStableInsets;
                 displayCutout = mPendingDisplayCutout.get();
             }
-            Rect outsets = mAttachInfo.mOutsets;
-            if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
-                contentInsets = new Rect(contentInsets.left + outsets.left,
-                        contentInsets.top + outsets.top, contentInsets.right + outsets.right,
-                        contentInsets.bottom + outsets.bottom);
-            }
             contentInsets = ensureInsetsNonNegative(contentInsets, "content");
             stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
             mLastWindowInsets = mInsetsController.calculateInsets(
@@ -2146,9 +2132,6 @@
                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
                 ensureTouchModeLocally(mAddedTouchMode);
             } else {
-                if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
-                    insetsChanged = true;
-                }
                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
                     insetsChanged = true;
                 }
@@ -2163,9 +2146,6 @@
                     if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
                             + mAttachInfo.mVisibleInsets);
                 }
-                if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
-                    insetsChanged = true;
-                }
                 if (mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars) {
                     insetsChanged = true;
                 }
@@ -2228,7 +2208,6 @@
 
         if (mApplyInsetsRequested) {
             mApplyInsetsRequested = false;
-            mLastOverscanRequested = mAttachInfo.mOverscanRequested;
             dispatchApplyInsets(host);
             if (mLayoutRequested) {
                 // Short-circuit catching a new layout request here, so
@@ -2292,8 +2271,6 @@
                     && !PixelFormat.formatHasAlpha(params.format)) {
                 params.format = PixelFormat.TRANSLUCENT;
             }
-            mAttachInfo.mOverscanRequested =
-                    (params.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
         }
 
         if (mFirst || windowShouldResize || insetsChanged ||
@@ -2342,12 +2319,10 @@
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
-                        + " overscan=" + mPendingOverscanInsets.toShortString()
                         + " content=" + mPendingContentInsets.toShortString()
                         + " visible=" + mPendingVisibleInsets.toShortString()
                         + " stable=" + mPendingStableInsets.toShortString()
                         + " cutout=" + mPendingDisplayCutout.get().toString()
-                        + " outsets=" + mPendingOutsets.toShortString()
                         + " surface=" + mSurface);
 
                 // If the pending {@link MergedConfiguration} handed back from
@@ -2363,8 +2338,6 @@
                     updatedConfiguration = true;
                 }
 
-                final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
-                        mAttachInfo.mOverscanInsets);
                 contentInsetsChanged = !mPendingContentInsets.equals(
                         mAttachInfo.mContentInsets);
                 final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
@@ -2373,7 +2346,6 @@
                         mAttachInfo.mStableInsets);
                 final boolean cutoutChanged = !mPendingDisplayCutout.equals(
                         mAttachInfo.mDisplayCutout);
-                final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
                 surfaceSizeChanged = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
                 final boolean alwaysConsumeSystemBarsChanged =
@@ -2389,13 +2361,6 @@
                     if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
                             + mAttachInfo.mContentInsets);
                 }
-                if (overscanInsetsChanged) {
-                    mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
-                    if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
-                            + mAttachInfo.mOverscanInsets);
-                    // Need to relayout with content insets.
-                    contentInsetsChanged = true;
-                }
                 if (stableInsetsChanged) {
                     mAttachInfo.mStableInsets.set(mPendingStableInsets);
                     if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
@@ -2416,12 +2381,8 @@
                     contentInsetsChanged = true;
                 }
                 if (contentInsetsChanged || mLastSystemUiVisibility !=
-                        mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
-                        || mLastOverscanRequested != mAttachInfo.mOverscanRequested
-                        || outsetsChanged) {
+                        mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
-                    mLastOverscanRequested = mAttachInfo.mOverscanRequested;
-                    mAttachInfo.mOutsets.set(mPendingOutsets);
                     mApplyInsetsRequested = false;
                     dispatchApplyInsets(host);
                     // We applied insets so force contentInsetsChanged to ensure the
@@ -4671,12 +4632,10 @@
                     // Recycled in the fall through...
                     SomeArgs args = (SomeArgs) msg.obj;
                     if (mWinFrame.equals(args.arg1)
-                            && mPendingOverscanInsets.equals(args.arg5)
                             && mPendingContentInsets.equals(args.arg2)
                             && mPendingStableInsets.equals(args.arg6)
                             && mPendingDisplayCutout.get().equals(args.arg9)
                             && mPendingVisibleInsets.equals(args.arg3)
-                            && mPendingOutsets.equals(args.arg7)
                             && mPendingBackDropFrame.equals(args.arg8)
                             && args.arg4 == null
                             && args.argi1 == 0
@@ -4706,20 +4665,16 @@
                         }
 
                         final boolean framesChanged = !mWinFrame.equals(args.arg1)
-                                || !mPendingOverscanInsets.equals(args.arg5)
                                 || !mPendingContentInsets.equals(args.arg2)
                                 || !mPendingStableInsets.equals(args.arg6)
                                 || !mPendingDisplayCutout.get().equals(args.arg9)
-                                || !mPendingVisibleInsets.equals(args.arg3)
-                                || !mPendingOutsets.equals(args.arg7);
+                                || !mPendingVisibleInsets.equals(args.arg3);
 
                         setFrame((Rect) args.arg1);
-                        mPendingOverscanInsets.set((Rect) args.arg5);
                         mPendingContentInsets.set((Rect) args.arg2);
                         mPendingStableInsets.set((Rect) args.arg6);
                         mPendingDisplayCutout.set((DisplayCutout) args.arg9);
                         mPendingVisibleInsets.set((Rect) args.arg3);
-                        mPendingOutsets.set((Rect) args.arg7);
                         mPendingBackDropFrame.set((Rect) args.arg8);
                         mForceNextWindowRelayout = args.argi1 != 0;
                         mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
@@ -7174,8 +7129,8 @@
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
-                mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
-                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
+                mTmpFrame, mPendingContentInsets, mPendingVisibleInsets,
+                mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout,
                 mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
         if (mSurfaceControl.isValid()) {
             if (USE_BLAST_BUFFERQUEUE == false) {
@@ -7198,7 +7153,6 @@
 
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame);
-            mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
             mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
             mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
             mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
@@ -7493,8 +7447,8 @@
     }
 
     @UnsupportedAppUsage
-    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+    private void dispatchResized(Rect frame, Rect contentInsets,
+            Rect visibleInsets, Rect stableInsets, boolean reportDraw,
             MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
             boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) {
@@ -7519,7 +7473,6 @@
         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWindow(frame);
-            mTranslator.translateRectInScreenToAppWindow(overscanInsets);
             mTranslator.translateRectInScreenToAppWindow(contentInsets);
             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
         }
@@ -7530,9 +7483,7 @@
         args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
         args.arg4 = sameProcessCall && mergedConfiguration != null
                 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
-        args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
         args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
-        args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
         args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
         args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
         args.argi1 = forceLayout ? 1 : 0;
@@ -8637,15 +8588,15 @@
         }
 
         @Override
-        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+        public void resized(Rect frame, Rect contentInsets,
+                Rect visibleInsets, Rect stableInsets, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
                 boolean alwaysConsumeSystemBars, int displayId,
                 DisplayCutout.ParcelableWrapper displayCutout) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
-                viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
-                        visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
+                viewAncestor.dispatchResized(frame, contentInsets,
+                        visibleInsets, stableInsets, reportDraw, mergedConfiguration,
                         backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId,
                         displayCutout);
             }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0e786b6..c62e69c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1445,7 +1445,10 @@
          * position its UI elements with this overscan flag is set:</p>
          *
          * {@sample development/samples/ApiDemos/res/layout/overscan_activity.xml complete}
+         *
+         * @deprecated Overscan areas aren't set by any Android product anymore.
          */
+        @Deprecated
         public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
 
         /**
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 403bfda..0ff6063 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -90,7 +90,7 @@
     @Override
     public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
-            Rect outStableInsets, Rect outOutsets,
+            Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState) {
         final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
@@ -140,8 +140,8 @@
     @Override
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
-            Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
+            Rect outStableInsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         State state = null;
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index cd2806a..6a706f5 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -70,6 +70,24 @@
     }
 
     @Override
+    public ConversationActions suggestConversationActions(ConversationActions.Request request) {
+        checkDestroyed();
+        return mDelegate.suggestConversationActions(request);
+    }
+
+    @Override
+    public TextLanguage detectLanguage(TextLanguage.Request request) {
+        checkDestroyed();
+        return mDelegate.detectLanguage(request);
+    }
+
+    @Override
+    public int getMaxGenerateLinksTextLength() {
+        checkDestroyed();
+        return mDelegate.getMaxGenerateLinksTextLength();
+    }
+
+    @Override
     public void onSelectionEvent(SelectionEvent event) {
         try {
             if (mEventHelper.sanitizeEvent(event)) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index a428fea..882e81a 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1267,12 +1267,12 @@
      * current value is set to the {@link NumberPicker#getMaxValue()} value.
      * </p>
      * <p>
-     * If the argument is less than the {@link NumberPicker#getMaxValue()} and
+     * If the argument is more than the {@link NumberPicker#getMaxValue()} and
      * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the
      * current value is set to the {@link NumberPicker#getMaxValue()} value.
      * </p>
      * <p>
-     * If the argument is less than the {@link NumberPicker#getMaxValue()} and
+     * If the argument is more than the {@link NumberPicker#getMaxValue()} and
      * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the
      * current value is set to the {@link NumberPicker#getMinValue()} value.
      * </p>
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index b02563a..c33b6dc 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -236,7 +236,6 @@
     ViewGroup mContentRoot;
 
     private Rect mTempRect;
-    private Rect mOutsets = new Rect();
 
     // This is the caption view for the window, containing the caption and window control
     // buttons. The visibility of this decor depends on the workspace and the window type.
@@ -729,24 +728,6 @@
             }
         }
 
-        getOutsets(mOutsets);
-        if (mOutsets.top > 0 || mOutsets.bottom > 0) {
-            int mode = MeasureSpec.getMode(heightMeasureSpec);
-            if (mode != MeasureSpec.UNSPECIFIED) {
-                int height = MeasureSpec.getSize(heightMeasureSpec);
-                heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        height + mOutsets.top + mOutsets.bottom, mode);
-            }
-        }
-        if (mOutsets.left > 0 || mOutsets.right > 0) {
-            int mode = MeasureSpec.getMode(widthMeasureSpec);
-            if (mode != MeasureSpec.UNSPECIFIED) {
-                int width = MeasureSpec.getSize(widthMeasureSpec);
-                widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        width + mOutsets.left + mOutsets.right, mode);
-            }
-        }
-
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
         int width = getMeasuredWidth();
@@ -785,13 +766,6 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        getOutsets(mOutsets);
-        if (mOutsets.left > 0) {
-            offsetLeftAndRight(-mOutsets.left);
-        }
-        if (mOutsets.top > 0) {
-            offsetTopAndBottom(-mOutsets.top);
-        }
         if (mApplyFloatingVerticalInsets) {
             offsetTopAndBottom(mFloatingInsets.top);
         }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index c8ba0a0..227ef28 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2378,10 +2378,6 @@
                     & (~getForcedWindowFlags()));
         }
 
-        if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
-            setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
-        }
-
         if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
             setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
         }
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
deleted file mode 100644
index 5f390be..0000000
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.android.internal.util;
-
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.view.ViewRootImpl;
-
-/**
- * @hide
- */
-public class ScreenShapeHelper {
-    /**
-     * Return the bottom pixel window outset of a window given its style attributes.
-     * @return An outset dimension in pixels or 0 if no outset should be applied.
-     */
-    public static int getWindowOutsetBottomPx(Resources resources) {
-        if (Build.IS_EMULATOR) {
-            return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
-        } else {
-            return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 7e1f13a..c7cdc3b 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -49,8 +49,8 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, Rect outsets, boolean reportDraw,
+    public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+            Rect stableInsets, boolean reportDraw,
             MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
             boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d5cd278..c807e90 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -545,6 +545,14 @@
     transaction->setLayerStack(ctrl, layerStack);
 }
 
+static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
+         jlong nativeObject, jfloat shadowRadius) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+    const auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    transaction->setShadowRadius(ctrl, shadowRadius);
+}
+
 static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
     const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
     jlongArray array = env->NewLongArray(displayIds.size());
@@ -1308,6 +1316,8 @@
             (void*)nativeSetCornerRadius },
     {"nativeSetLayerStack", "(JJI)V",
             (void*)nativeSetLayerStack },
+    {"nativeSetShadowRadius", "(JJF)V",
+            (void*)nativeSetShadowRadius },
     {"nativeGetPhysicalDisplayIds", "()[J",
             (void*)nativeGetPhysicalDisplayIds },
     {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 97dae59..9e0c35a 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2436,4 +2436,9 @@
     // OS: R
     INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
 
+    // OPEN: Settings > Apps and notifications > Special app access > notification access >
+    // an app
+    // CATEGORY: SETTINGS
+    // OS: R
+    NOTIFICATION_ACCESS_DETAIL = 1804;
 }
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 8f084ab..ce2717b 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -126,11 +126,12 @@
     optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
     optional .com.android.server.wm.IdentifierProto identifier = 2;
     optional string state = 3;
-    optional bool visible = 4;
+    optional bool visible_requested = 4;
     optional bool front_of_task = 5;
     optional int32 proc_id = 6;
     optional bool translucent = 7;
     optional .com.android.server.wm.AppWindowTokenProto app_window_token = 8;
+    optional bool visible = 9;
 }
 
 message KeyguardControllerProto {
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c9a1829..553fc73 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -235,7 +235,7 @@
     optional WindowContainerThumbnailProto thumbnail = 6;
     optional bool fills_parent = 7;
     optional bool app_stopped = 8;
-    optional bool hidden_requested = 9;
+    optional bool visible_requested = 9;
     optional bool client_hidden = 10;
     optional bool defer_hiding_client = 11;
     optional bool reported_drawn = 12;
@@ -248,8 +248,9 @@
     optional IdentifierProto starting_window = 19;
     optional bool starting_displayed = 20;
     optional bool starting_moved = 21;
-    optional bool hidden_set_from_transferred_starting_window = 22;
+    optional bool visible_set_from_transferred_starting_window = 22;
     repeated .android.graphics.RectProto frozen_bounds = 23;
+    optional bool visible = 24;
 }
 
 /* represents WindowToken */
@@ -259,7 +260,6 @@
     optional WindowContainerProto window_container = 1;
     optional int32 hash_code = 2;
     repeated WindowStateProto windows = 3;
-    optional bool hidden = 4;
     optional bool waiting_to_show = 5;
     optional bool paused = 6;
 }
@@ -385,12 +385,12 @@
     optional .android.graphics.RectProto display_frame = 4;
     optional .android.graphics.RectProto frame = 5;
     optional .android.graphics.RectProto outset_frame = 6;
-    optional .android.graphics.RectProto overscan_frame = 7;
+    optional .android.graphics.RectProto overscan_frame = 7 [deprecated=true];
     optional .android.graphics.RectProto parent_frame = 8;
     optional .android.graphics.RectProto visible_frame = 9;
     optional .android.view.DisplayCutoutProto cutout = 10;
     optional .android.graphics.RectProto content_insets = 11;
-    optional .android.graphics.RectProto overscan_insets = 12;
+    optional .android.graphics.RectProto overscan_insets = 12 [deprecated=true];
     optional .android.graphics.RectProto visible_insets = 13;
     optional .android.graphics.RectProto stable_insets = 14;
     optional .android.graphics.RectProto outsets = 15;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index d010c8f..004b096 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -119,6 +119,9 @@
 
         // The package that requested the installation of this one.
         optional string initiating_package_name = 1;
+
+        // The package on behalf of which the initiiating package requested the install.
+        optional string originating_package_name = 2;
     }
 
     // Name of package. e.g. "com.android.providers.telephony".
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d70fbc..9f77407 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2007,7 +2007,7 @@
     <eat-comment />
 
     <!-- @SystemApi Allows granting runtime permissions to telephony related components.
-         @hide Used internally. -->
+         @hide -->
     <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
         android:protectionLevel="signature|telephony" />
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2b20a6b..485162c 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Opgedateer deur jou administrateur"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Uitgevee deur jou administrateur"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Skakel Databespaarder aan?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Skakel aan"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Regstreekse deling is nie beskikbaar nie"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programmelys"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Opneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2588814..f0a4307 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"እሺ"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ውሂብ ቆጣቢ ይጥፋ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"አብራ"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ቀጥታ ማጋራት አይገኝም"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"የመተግበሪያዎች ዝርዝር"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ይህ መተግበሪያ የመቅረጽ ፈቃድ አልተሰጠውም፣ ነገር ግን በዚህ ዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅረጽ ይችላል።"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 162c066..4ecf6e7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1863,10 +1863,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"تم التحديث بواسطة المشرف"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"تم الحذف بواسطة المشرف"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"موافق"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"هل تريد تشغيل توفير البيانات؟"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"تشغيل"</string>
@@ -2144,4 +2142,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"لا تتوفّر إمكانية المشاركة المباشرة."</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"قائمة التطبيقات"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏لم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 2ae2ad4..81a04b7 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"পোনপটীয়া শ্বেয়াৰৰ সুবিধা নাই"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"এপ্‌সমূহৰ সূচী"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 2f8cd99..9f43c36 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Admin tərəfindən yeniləndi"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Admin tərəfindən silindi"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsini və qəbulunun qarşısını alır. Hazırda istifadə etdiyiniz tətbiq dataya daxil ola bilər, lakin bunu tez-tez edə bilməz. Bu o deməkdir ki, məsələn, Siz üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Data Qənaəti aktiv edilsin?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivləşdirin"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Birbaşa paylaşım əlçatan deyil"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Tətbiq siyahısı"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu tətbiqə yazmaq icazəsi verilməyib, lakin, bu USB vasitəsilə səs yaza bilər."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9c13758..a6ad733 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1794,10 +1794,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je administrator"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je administrator"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Potvrdi"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2042,4 +2040,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno deljenje nije dostupno"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacija"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ova aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 48ca6df..92cad08 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Абноўлены вашым адміністратарам"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Выдалены вашым адміністратарам"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"У рэжыме Эканомія трафіка фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Уключыць Эканомію трафіка?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Уключыць"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Непасрэднае абагульванне недаступнае"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Спіс праграм"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"У гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту USB-прыладу."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1d6e7f1..9a4ca0c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Актуализирано от администратора ви"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Изтрито от администратора ви"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ще вкл. ли Икономия на данни?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Включване"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Няма възможност за директно споделяне"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Списък с приложения"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложението няма разрешение за записване, но може да записва звук чрез това USB устройство."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index bdb5572..4dc5f5c 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"আপনার প্রশাসক আপডেট করেছেন"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ঠিক আছে"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সেভার চালু করবেন?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"চালু করুন"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"সরাসরি শেয়ার করার সুবিধা নেই"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"অ্যাপের তালিকা"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 03a4cc5..ea4d209 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1796,10 +1796,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je vaš administrator"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je vaš administrator"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Uredu"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2044,4 +2042,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno dijeljenje nije dostupno"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Spisak aplikacija"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ovoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fd07668..4f9eeb8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualitzat per l\'administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Suprimit per l\'administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"D\'acord"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"\n\n"<annotation id="url">"Més informació"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Activar Economitzador de dades?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activa"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"La compartició directa no està disponible"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Llista d\'aplicacions"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e2f03df..502a7a8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizováno administrátorem"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Smazáno administrátorem"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“\n\n"<annotation id="url">"Další informace"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnout Spořič dat?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnout"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Přímé sdílení není k dispozici"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikací"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3916f1e..d347e35 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Opdateret af din administrator"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet af din administrator"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå Datasparefunktion til?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Slå til"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Det er ikke muligt at dele direkte"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste over apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 9635b2d..b4b40ea 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share nicht verfügbar"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste der Apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Diese App hat noch keine Berechtigung zum Aufnehmen erhalten, könnte aber Audioaufnahmen über dieses USB-Gerät machen."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2766ce4..73828a1 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ενημερώθηκε από τον διαχειριστή σας"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Διαγράφηκε από τον διαχειριστή σας"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\".\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ενεργοποίηση"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Η άμεση κοινοποίηση δεν είναι διαθέσιμη"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Λίστα εφαρμογών"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index dba1353..9163214 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4ecafc9..dff558f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index dba1353..9163214 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index dba1353..9163214 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 331133a..7519ad6 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2006,4 +2006,13 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‎Direct share not available‎‏‎‎‏‎"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎Apps list‎‏‎‎‏‎"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎This app has not been granted record permission but could capture audio through this USB device.‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_home_label" msgid="6089400419441597916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎Home‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_back_label" msgid="8986628898117178971">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎Back‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_recents_label" msgid="7607601657790855723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎Recent Apps‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_notifications_label" msgid="1578681904050072545">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎Notifications‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_quick_settings_label" msgid="3885565587471448947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎Quick Settings‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_power_dialog_label" msgid="2299530700682199873">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎Power Dialog‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_toggle_split_screen_label" msgid="2853334443686935668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎Toggle Split Screen‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_lock_screen_label" msgid="2377933717780192594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎Lock Screen‎‏‎‎‏‎"</string>
+    <string name="accessibility_system_action_screenshot_label" msgid="1933564892301816480">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎Screenshot‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f5fc145..0381249 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Tu administrador actualizó este paquete"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Tu administrador borró este paquete"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para reducir el uso de datos, Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar Ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No está disponible el uso compartido directo"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cfac5dc..7f152e1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se mostrarán hasta que las toques."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No se puede compartir directamente"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicaciones"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación no tiene permiso para grabar, pero podría registrar audio con este dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8193339..a48c482 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Administraator on seda värskendanud"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administraator on selle kustutanud"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Lül. andmemahu säästja sisse?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Lülita sisse"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Vahetu jagamine ei ole saadaval"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Rakenduste loend"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ca79d05..805df6e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -70,7 +70,7 @@
     <string name="ThreeWCMmi" msgid="9051047170321190368">"Hiru hizlaritako deiak"</string>
     <string name="RuacMmi" msgid="7827887459138308886">"Nahigabeko dei gogaikarriak ukatzea"</string>
     <string name="CndMmi" msgid="3116446237081575808">"Deitzailearen zenbakia ematea"</string>
-    <string name="DndMmi" msgid="1265478932418334331">"Ez molestatu"</string>
+    <string name="DndMmi" msgid="1265478932418334331">"Ez molestatzeko modua"</string>
     <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenekin"</string>
     <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenik gabe"</string>
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenekin"</string>
@@ -653,8 +653,8 @@
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Operadore baten mezularitza-zerbitzuaren goi-mailako interfazeari lotzea baimentzen die erabiltzaileei. Aplikazio normalek ez lukete inoiz beharko."</string>
     <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"lotu operadorearen zerbitzuei"</string>
     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Operadorearen zerbitzuei lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string>
-    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu \"Ez molestatu\" egoera"</string>
-    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"Ez molestatu\" konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
+    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu ez molestatzeko modua"</string>
+    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ez molestatzeko moduaren konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"hasi ikusteko baimena erabiltzen"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Aplikazioaren baimena erabiltzen hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string>
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratzaileak ezabatu du"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Ados"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Unean erabiltzen ari zaren aplikazioak atzitu egin ahal izango ditu datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Datu-aurrezlea aktibatu?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktibatu"</string>
@@ -1813,10 +1811,10 @@
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
     <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte (hurrengo alarma)"</string>
     <string name="zen_mode_forever" msgid="931849471004038757">"Zuk desaktibatu arte"</string>
-    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Ez molestatu\" desaktibatzen duzun arte"</string>
+    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Ez molestatzeko modua desaktibatzen duzun arte"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Tolestu"</string>
-    <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatu"</string>
+    <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatzeko modua"</string>
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Jarduerarik gabeko denbora"</string>
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Lanegunetako gaua"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Asteburua"</string>
@@ -1958,10 +1956,10 @@
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Dar-dar egingo du deiak eta jakinarazpenak jasotzean"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Ez da joko tonurik deiak eta jakinarazpenak jasotzean"</string>
     <string name="notification_channel_system_changes" msgid="5072715579030948646">"Sistema-aldaketak"</string>
-    <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatu"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: \"Ez molestatu\" modua jakinarazpenak ezkutatzen ari da"</string>
+    <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatzeko modua"</string>
+    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: Ez molestatzeko modua jakinarazpenak ezkutatzen ari da"</string>
     <string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Sakatu informazio gehiago lortzeko eta portaera aldatzeko."</string>
-    <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\"Ez molestatu\" modua aldatu da"</string>
+    <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Ez molestatzeko modua aldatu da"</string>
     <string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Sakatu zer dagoen blokeatuta ikusteko."</string>
     <string name="notification_app_name_system" msgid="4205032194610042794">"Sistema"</string>
     <string name="notification_app_name_settings" msgid="7751445616365753381">"Ezarpenak"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Zuzenean partekatzeko aukera ez dago erabilgarri"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Aplikazioen zerrenda"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a9231e9..98044c6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"توسط سرپرست سیستم حذف شد"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"تأیید"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n «طرح زمینه تیره» را روشن می‌کند\n فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n «طرح زمینه تیره» را روشن می‌کند\n فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"برای کمک به کاهش مصرف داده، «صرفه‌جویی داده» از ارسال و دریافت داده در پس‌زمینه ازطرف بعضی برنامه‌ها جلوگیری می‌کند. برنامه‌ای که درحال‌حاضر استفاده می‌کنید می‌تواند به داده‌ها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تا زمانی که روی آن‌ها ضربه نزنید نشان داده نمی‌شوند."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"صرفه‌جویی داده روشن شود؟"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"روشن کردن"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"اشتراک‌گذاری مستقیم دردسترس نیست"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"فهرست برنامه‌ها"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏مجوز ضبط به این برنامه داده نشده است اما می‌تواند صدا را ازطریق این دستگاه USB ضبط کند."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 14ed7b7..3476bf5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Järjestelmänvalvoja päivitti tämän."</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Järjestelmänvalvoja poisti tämän."</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google)."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Otetaanko Data Saver käyttöön?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ota käyttöön"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Suora jakaminen ei käytettävissä"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Sovellusluettelo"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sovellus ei ole saanut tallennuslupaa mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2c4362d..702ecc0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Mise à jour par votre administrateur"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Supprimé par votre administrateur"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Pour aider à diminuer l\'utilisation des données, la fonction Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'Économiseur de données?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index cbb64e6..eb199de 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 848cd0b..9659973 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado polo teu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado polo teu administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\"\n\n"<annotation id="url">"Máis información"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para contribuír a reducir o uso de datos, o Economizador de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Queres activar o economizador de datos?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Non está dispoñible a función de compartir directamente"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicacións"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2a5536f..6dab622 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ઓકે"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપ્લિકેશનોને પૃષ્ઠભૂમિમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ્લિકેશન ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ડેટા સેવર ચાલુ કરીએ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ચાલુ કરો"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ડાયરેક્ટ શેર કરવાનું ઉપલબ્ધ નથી"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ઍપની સૂચિ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"આ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફતે ઑડિયો કૅપ્ચર કરી શકે છે."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 698a6a7..1a082b9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"आपके व्यवस्थापक ने अपडेट किया है"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"आपके व्यवस्थापक ने हटा दिया है"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ठीक है"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n·गहरे रंग वाली थीम चालू करता है\n·बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n गहरे रंग वाली थीम चालू करता है\nबैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"डेटा खर्च, कम करने के लिए डेटा सेवर कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकता है. आप फ़िलहाल जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा तक पहुंच सकता है लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन्हें टैप नहीं करते."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचाने की सेटिंग चालू करें?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करें"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधे शेयर नहीं किया जा सकता"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ऐप्लिकेशन की सूची"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"इस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऐसा कर सकता है."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6a134dc..56d5b20 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1794,10 +1794,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao administrator"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao administrator"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"U redu"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2042,4 +2040,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Izravno dijeljenje nije dostupno"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Popis aplikacija"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem ovog USB uređaja."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0cd3fec..184b66a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"A rendszergazda által frissítve"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"A rendszergazda által törölve"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által aktuálisan használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Bekapcsolás"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A közvetlen megosztás nem áll rendelkezésre"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Alkalmazások listája"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ez az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a923814..fef6f4e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share գործառույթը հասանելի չէ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Հավելվածների ցանկ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Հավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b25b643..87a8804 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Oke"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan kuota, Penghemat Kuota Internet mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Kuota?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Berbagi langsung tidak tersedia"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Daftar aplikasi"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index c2ffddf..a37eda6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bein deiling er ekki tiltæk"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Forritalisti"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Þetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2e672dc..2b780d0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Aggiornato dall\'amministratore"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminato dall\'amministratore"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Attivare Risparmio dati?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Attiva"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Condivisione diretta non disponibile"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Elenco di app"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fdf34e0..dfbf834 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"עודכנה על ידי מנהל המערכת"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"נמחקה על ידי מנהל המערכת"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"אישור"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"‏התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"‏האם להפעיל את חוסך הנתונים (Data Saver)?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"הפעל"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"שיתוף ישיר אינו זמין"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"רשימת האפליקציות"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏לאפליקציה זו לא ניתנה הרשאת הקלטה, אבל אפשר להקליט אודיו באמצעות התקן ה-USB הזה."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 07c8107..4776980 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"管理者により更新されています"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"管理者により削除されています"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"データセーバーを ON にしますか?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ON にする"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ダイレクト シェアは利用できません"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"アプリのリスト"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"このアプリに録音権限は付与されていませんが、この USB デバイスから音声を収集できるようになります。"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 87bd222..7f06b01 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"პირდაპირი გაზიარება მიუწვდომელია"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"აპების სია"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b3395df..65da546 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Әкімші жаңартқан"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Әкімші жойған"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Жарайды"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Дерек шығынын азайту үшін Data Saver функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге және алуға жол бермейді. Ашық тұрған қолданба деректерді пайдаланады, бірақ шектеулі шамада (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Data Saver функциясын қосу керек пе?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Қосу"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Тікелей бөлісу мүмкін емес."</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Қолданбалар тізімі"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Қолданбаға жазу рұқсаты берілмеді, бірақ ол осы USB құрылғысы арқылы дыбыс жаза алады."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3eb71f6..32b3ee1 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1773,10 +1773,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"យល់ព្រម"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំ​ថ្ម៖\n·បើករចនាប័ទ្មងងឹត​\n·បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Hey Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំ​ថ្ម៖\n·បើករចនាប័ទ្មងងឹត​\n·បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Hey Google” ជាដើម"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់​ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យឬ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"បើក"</string>
@@ -2010,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"មិនមាន​ការចែករំលែក​ដោយផ្ទាល់ទេ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"បញ្ជីកម្មវិធី"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"កម្មវិធីនេះ​មិនទាន់បាន​ទទួលសិទ្ធិ​ថតសំឡេង​នៅឡើយទេ ប៉ុន្តែអាច​ថតសំឡេង​តាមរយៈ​ឧបករណ៍ USB នេះបាន។"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index a1d993d..0fab683 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ಸರಿ"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ಡೇಟಾ ಉಳಿಸುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡುವುದೇ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ಆನ್‌ ಮಾಡಿ"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ನೇರ ಹಂಚಿಕೆ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bb1c1e7..f42a928 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"관리자에 의해 업데이트되었습니다."</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"관리자에 의해 삭제되었습니다."</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"확인"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"데이터 절약 모드를 사용할까요?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"사용 설정"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"직접 공유가 지원되지 않음"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"앱 목록"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f8191de..82064b2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1772,10 +1772,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Администраторуңуз жаңыртып койгон"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Администраторуңуз жок кылып салган"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ЖАРАЙТ"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Трафикти үнөмдөө режиминде айрым колдонмолор дайындарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайындарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Трафикти үнөмдөө режимин иштетесизби?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Күйгүзүү"</string>
@@ -2009,4 +2007,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Түздөн-түз бөлүшүүгө болбойт"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Колдонмолордун тизмеси"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Бул колдонмонун жаздырууга уруксаты жок, бирок бул USB түзмөгү аркылуу аудиону жаздыра алат."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d6150cb..3aa786e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2006,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ບໍ່ສາມາດແບ່ງປັນໂດຍກົງໄດ້"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ລາຍຊື່ແອັບ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ແອັບນີ້ບໍ່ໄດ້ຮັບສິດອະນຸຍາດໃນການບັນທຶກ ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8bcb000..d4d19f4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atnaujino administratorius"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Ištrynė administratorius"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Gerai"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Įj. Duomenų taupymo priemonę?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Įjungti"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiesioginio bendrinimo funkcija nepasiekiama"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programų sąrašas"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a936bcc..89a98dd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1794,10 +1794,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atjaunināja administrators"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dzēsa administrators"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Labi"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ieslēgt"</string>
@@ -2042,4 +2040,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiešā kopīgošana nav pieejama"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lietotņu saraksts"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index e4bfdf4..4396c08 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1773,10 +1773,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирано од администраторот"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Избришано од администраторот"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Во ред"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Апликацијата што ја користите во моментов можеби ќе пристапува до интернет, но тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажат додека не ги допрете."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Вклучете Штедач на интернет?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Вклучи"</string>
@@ -2010,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Не е достапно директно споделување"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список со апликации"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"На апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 6957879..0b33971 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ശരി"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്‌സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദ‍‍‍ർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ഓണാക്കുക"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"നേരിട്ടുള്ള പങ്കിടൽ ലഭ്യമല്ല"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ആപ്പുകളുടെ ലിസ്‌റ്റ്"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f1077c5..990a4d0 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Таны админ шинэчилсэн"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Таны админ устгасан"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь зарим апп-н өгөгдлийг дэвсгэрт илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Жишээлбэл зургийг товших хүртэл харагдахгүй."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Дата хэмнэгчийг асаах уу?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Асаах"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Шууд хуваалцах боломжгүй"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Аппын жагсаалт"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Энэ апликейшнд бичих зөвшөөрөл олгогдоогүй ч энэ USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 6b17e27..edc89a4 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"आपल्या प्रशासकाने अपडेट केले"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"आपल्या प्रशासकाने हटवले"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ओके"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बॅटरी सेव्‍हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"बॅटरी सेव्‍हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"डेटा सर्व्हर डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अ‍ॅप्सना पार्श्वभूमीमध्ये डेटा पाठवण्यास किंवा  मिळवण्यास प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अ‍ॅप डेटा अ‍ॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असा असू शकतो."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा सेव्हर चालू करायचा?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करा"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"थेट शेअर करणे उपलब्ध नाही"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अ‍ॅप्स सूची"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 37d5ef1..0c881c5 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Dikemas kini oleh pentadbir anda"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dipadamkan oleh pentadbir anda"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Hidupkan Penjimat Data?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Hidupkan"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Perkongsian langsung tidak tersedia"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Senarai apl"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Apl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 8e154b9..f5745b5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ဒေတာအသုံးပြုမှု ချွေတာမှုစနစ်ကို ဖွင့်မလား။"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ဖွင့်ပါ"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"တိုက်ရိုက်မျှဝေ၍ မရပါ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"အက်ပ်စာရင်း"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d9d59ea..0359779 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Oppdatert av administratoren din"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet av administratoren din"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå på Datasparing?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Slå på"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktedeling er ikke tilgjengelig"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Appliste"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2b61999..2617086 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2014,4 +2014,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधै आदान प्रदान गर्ने सुविधा उपलब्ध छैन"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अनुप्रयोगहरूको सूची"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"यो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5922388..43b4ede 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Geüpdatet door je beheerder"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Verwijderd door je beheerder"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n·Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Databesparing inschakelen?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Inschakelen"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Rechtstreeks delen is niet beschikbaar"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lijst met apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Deze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 04d5652..68b76c8 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ସିଧାସଳଖ ସେୟାର୍ ସୁବିଧା ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ଆପ୍ସ ତାଲିକା"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍‍ଚର୍‍ କରିପାରିବ।"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 2cc004c..63b5f53 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ਠੀਕ ਹੈ"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ਚਾਲੂ ਕਰੋ"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ਸਿੱਧਾ ਸਾਂਝਾ ਕਰਨ ਦੀ ਸੁਵਿਧਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ਐਪ ਸੂਚੀ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a5d8125..bd695a9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Zaktualizowany przez administratora"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Usunięty przez administratora"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny, \nwyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny,\n wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Włączyć Oszczędzanie danych?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Włącz"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Udostępnianie bezpośrednie jest niedostępne"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacji"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9c44862..45a2abd2 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6a695a7..0fd303f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu gestor"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado pelo seu gestor"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saber mais"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada aplicação que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar a Poupança de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A partilha direta não está disponível."</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicações"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9c44862..45a2abd2 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 35ce5d6..a878628 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1794,10 +1794,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizat de administratorul dvs."</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Șters de administratorul dvs."</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Activați Economizorul de date?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Activați"</string>
@@ -2042,4 +2040,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Trimiterea directă nu este disponibilă"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicații"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0fcb4c9..aa94aa6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Обновлено администратором"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Удалено администратором"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"В режиме экономии трафика фоновая передача для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Включить экономию трафика?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Включить"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Функция Direct Share недоступна."</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список приложений"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложению не разрешено записывать звук, однако оно может делать это с помощью этого USB-устройства."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index aaff63f..ee261a54 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1773,10 +1773,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"හරි"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්‍රියාත්මක කරයි\n·පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්‍රියාත්මක කරයි\n·පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"දත්ත සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"ක්‍රියාත්මක කරන්න"</string>
@@ -2010,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ඍජු බෙදා ගැනීම නොලැබේ"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"යෙදුම් ලැයිස්තුව"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්‍රව්‍ය ග්‍රහණය කර ගත හැකිය."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 84b2874..ed4f68c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizoval správca"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Odstránil správca"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnúť šetrič dát?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnúť"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Priame zdieľanie nie je k dispozícii"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Zoznam aplikácií"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4657001..dc162a8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Posodobil skrbnik"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisal skrbnik"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"V redu"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vklop varčevanja s podatki?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Vklop"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Neposredna skupna raba ni na voljo"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikacij"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cdef310..4973f9f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ndarja e drejtpërdrejtë nuk ofrohet"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista e aplikacioneve"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Këtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c953e5e..48658bb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1794,10 +1794,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирао је администратор"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Избрисао је администратор"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Потврди"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Укључити Уштеду података?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Укључи"</string>
@@ -2042,4 +2040,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Директно дељење није доступно"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Листа апликација"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ова апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 32cd878..09a2513 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1414,7 +1414,7 @@
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Begärd behörighet"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Begärd behörighet\nför kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Du använder den här appen i din arbetsprofil"</string>
-    <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din profil"</string>
+    <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din jobbprofil"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Indatametod"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkronisera"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Administratören uppdaterade paketet"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratören raderade paketet"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas\n\n"<annotation id="url">"Läs mer"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktivera Databesparing?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivera"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Dela direkt är inte tillgängligt"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Applista"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Appen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 15bb4bf..483c39f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Imesasishwa na msimamizi wako"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Imefutwa na msimamizi wako"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Sawa"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Ungependa Kuwasha Kiokoa Data?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Washa"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Huwezi kushiriki moja kwa moja"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Orodha ya programu"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Programu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e2629df..0c4e20e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"சரி"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"இயக்கு"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"நேரடிப் பகிர்வு இல்லை"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ஆப்ஸ் பட்டியல்"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6718470..1b3df6e 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"డైరెక్ట్ షేర్ అందుబాటులో లేదు"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"యాప్‌ల జాబితా"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2f59711..ff1ea21 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"อัปเดตโดยผู้ดูแลระบบ"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"ลบโดยผู้ดูแลระบบ"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ตกลง"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"เปิด"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"การแชร์โดยตรงไม่พร้อมใช้งาน"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"รายชื่อแอป"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"แอปนี้ไม่ได้รับอนุญาตให้บันทึกเสียงแต่จะบันทึกเสียงผ่านอุปกรณ์ USB นี้ได้"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0fc1014..79c040f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Na-update ng iyong admin"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Na-delete ng iyong admin"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"I-on ang Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"I-on"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Hindi available ang direktang pagbabahagi"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Listahan ng mga app"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Hindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index f95d836..d6841f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Yöneticiniz tarafından güncellendi"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Yöneticiniz tarafından silindi"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Tamam"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Veri Tasarrufu açılsın mı?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aç"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Doğrudan paylaşım mevcut değil"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uygulama listesi"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu uygulamaya ses kaydetme izni verilmedi ancak bu USB cihazı üzerinden sesleri yakalayabilir."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d5cdb32..3412eb2 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1817,10 +1817,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Оновлено адміністратором"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Видалено адміністратором"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google.\n\n"<annotation id="url">"Докладніше"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Увімкнути Заощадження трафіку?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Увімкнути"</string>
@@ -2076,4 +2074,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Прямий обмін даними недоступний"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список додатків"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Цей додаток не має дозволу на запис, але він може фіксувати звук через цей USB-пристрій."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index ab2a83c..003fd54 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"ٹھیک ہے"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتا ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا پر رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا زیادہ نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"ڈیٹا سیور آن کریں؟"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"آن کریں"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"بلاواسطہ اشتراک دستیاب نہیں ہے"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ایپس کی فہرست"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏اس ایپ کو ریکارڈ کرنے کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ کے ذریعے آڈیو کیپچر کر سکتی ہے۔"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d618d99..83e99b9 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Administrator tomonidan yangilangan"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Administrator tomonidan o‘chirilgan"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Trafik tejash yoqilsinmi?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Yoqish"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bevosita ulashuv ishlamaydi"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Ilovalar roʻyxati"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9880890..7b17de7 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Không thể chia sẻ trực tiếp"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Danh sách ứng dụng"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ứng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1a9eec8..e29898f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2008,4 +2008,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"无法使用直接分享功能"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"应用列表"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a69e357..40f0c94 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"已由您的管理員更新"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"好"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟「數據節省模式」嗎?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法直接分享"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 507f696..2fb155e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"已由你的管理員更新"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"已由你的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"確定"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的某個應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟數據節省模式嗎?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法使用直接分享功能"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"這個應用程式未取得錄製內容的權限,但可以透過這部 USB 裝置錄製音訊。"</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c15224a..2ecc835 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1771,10 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Kubuyekezwe umlawuli wakho"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Kususwe umlawuli wakho"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"KULUNGILE"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (2307555792915978653) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ukuze unwebise impilo yebhethri, Isilondolozi Sebhethri:\n·Sivula itimu emnyama\n·Sivala noma sikhawulela umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"Ukuze unwebise impilo yebhethri, Isilondolozi sebhethri:\n·Vula itimu emnyama\n·Vala noma ukhawulele umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vula iseva yedatha?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Vula"</string>
@@ -2008,4 +2006,22 @@
     <string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ukwabelana okuqondile akutholakali"</string>
     <string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uhlu lwezinhlelo zokusebenza"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Lolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lungathwebula umsindo ngale divayisi ye-USB."</string>
+    <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+    <skip />
+    <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bad5d64..642dc92 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -359,7 +359,9 @@
              to {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}. -->
         <attr name="windowFullscreen" format="boolean" />
         <!-- Flag indicating whether this window should extend into overscan region.  Corresponds
-             to {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN}. -->
+             to {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN}.
+             @deprecated Overscan areas aren't set by any Android product anymore.
+             -->
         <attr name="windowOverscan" format="boolean" />
         <!-- Flag indicating whether this is a floating window. -->
         <attr name="windowIsFloating" format="boolean" />
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index 840a551..64483f1 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -29,9 +29,6 @@
     <!-- The alert controller to use for alert dialogs. -->
     <integer name="config_alertDialogController">0</integer>
 
-    <!-- True if windowOverscan should be on by default. -->
-    <bool name="config_windowOverscanByDefault">false</bool>
-
     <!-- True if preference fragment should clip to padding. -->
     <bool name="config_preferenceFragmentClipToPadding">true</bool>
 
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 78d218f..f3905e9 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -162,7 +162,6 @@
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
         <item name="windowFullscreen">false</item>
-        <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -536,7 +535,6 @@
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
         <item name="windowFullscreen">false</item>
-        <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -963,10 +961,11 @@
     <!-- Variant of the material (dark) theme that has no title bar and fills
          the entire screen and extends into the display overscan region.  This theme
          sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
+         to true.
+         @deprecated Overscan areas aren't set by any Android product anymore.
+         -->
     <style name="Theme.Material.NoActionBar.Overscan">
         <item name="windowFullscreen">true</item>
-        <item name="windowOverscan">true</item>
         <item name="windowContentOverlay">@null</item>
     </style>
 
@@ -996,10 +995,11 @@
     <!-- Variant of the material (light) theme that has no title bar and fills
          the entire screen and extends into the display overscan region.  This theme
          sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
+         to true.
+         @deprecated Overscan areas aren't set by any Android product anymore.
+         -->
     <style name="Theme.Material.Light.NoActionBar.Overscan">
         <item name="windowFullscreen">true</item>
-        <item name="windowOverscan">true</item>
         <item name="windowContentOverlay">@null</item>
     </style>
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index c2fa8b2b..17fe61d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -32,7 +32,6 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.truth.Truth;
 
@@ -43,6 +42,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -54,10 +54,19 @@
  * Tests are skipped if such a textclassifier does not exist.
  */
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class TextClassifierTest {
+    private static final String LOCAL = "local";
+    private static final String SESSION = "session";
 
-    // TODO: Implement TextClassifierService testing.
+    // TODO: Add SYSTEM, which tests TextClassifier.SYSTEM.
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object> textClassifierTypes() {
+        return Arrays.asList(LOCAL, SESSION);
+    }
+
+    @Parameterized.Parameter
+    public String mTextClassifierType;
 
     private static final TextClassificationConstants TC_CONSTANTS =
             new TextClassificationConstants(() -> "");
@@ -72,7 +81,17 @@
     public void setup() {
         mContext = InstrumentationRegistry.getTargetContext();
         mTcm = mContext.getSystemService(TextClassificationManager.class);
-        mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
+
+        if (mTextClassifierType.equals(LOCAL)) {
+            mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
+        } else {
+            mClassifier = mTcm.createTextClassificationSession(
+                    new TextClassificationContext.Builder(
+                            "android",
+                            TextClassifier.WIDGET_TYPE_NOTIFICATION)
+                            .build(),
+                    mTcm.getTextClassifier(TextClassifier.LOCAL));
+        }
     }
 
     @Test
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 753f8a0..b9a1346 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -73,18 +73,18 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1976550065": {
+      "message": "commitVisibility: %s: visible=%b visibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1963461591": {
       "message": "Removing %s from %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-1958209312": {
-      "message": "Clear freezing of %s: hidden=%b freezing=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "-1953668890": {
       "message": "Can't start recents animation, nextAppTransition=%s",
       "level": "DEBUG",
@@ -547,12 +547,6 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
-    "-931184679": {
-      "message": "Changing app %s hidden=%b performLayout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "-928291778": {
       "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
       "level": "VERBOSE",
@@ -841,6 +835,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "-374767836": {
+      "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-371630969": {
       "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
       "level": "VERBOSE",
@@ -1207,12 +1207,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "358613119": {
-      "message": "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "371641947": {
       "message": "Window Manager Crash %s",
       "level": "WTF",
@@ -1273,6 +1267,12 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "466506262": {
+      "message": "Clear freezing of %s: visible=%b freezing=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "474000473": {
       "message": "No stack above target stack=%s",
       "level": "DEBUG",
@@ -1489,6 +1489,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "841702299": {
+      "message": "Changing app %s visible=%b performLayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "845234215": {
       "message": "App is requesting an orientation, return %d for display id=%d",
       "level": "VERBOSE",
@@ -1501,12 +1507,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
-    "857751535": {
-      "message": "commitVisibility: %s: hidden=%b hiddenRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "873914452": {
       "message": "goodToGo()",
       "level": "DEBUG",
@@ -1903,6 +1903,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1746778201": {
+      "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "1747941491": {
       "message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s",
       "level": "INFO",
@@ -1993,12 +1999,6 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
-    "1966564525": {
-      "message": "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "1984470582": {
       "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
       "level": "DEBUG",
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ee8cc40..3c47835 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -1067,6 +1067,17 @@
         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
     }
 
+    /**
+     * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
+     */
+    public void onUserLockedStateChanged(int userHandle, boolean locked) {
+        try {
+            mBinder.onKeyguardVisibilityChanged(locked, userHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to update user locked state " + userHandle, e);
+        }
+    }
+
     private class KeyAttestationCallbackResult {
         private KeystoreResponse keystoreResponse;
         private KeymasterCertificateChain certificateChain;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 234615d..2cdd000 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
 package android.security.keystore;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.security.KeyStore;
 import android.security.keymaster.ExportResult;
@@ -52,8 +53,9 @@
  *
  * @hide
  */
+@SystemApi
 public class AndroidKeyStoreProvider extends Provider {
-    public static final String PROVIDER_NAME = "AndroidKeyStore";
+    private static final String PROVIDER_NAME = "AndroidKeyStore";
 
     // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
     // classes when this provider is instantiated and installed early on during each app's
@@ -68,6 +70,7 @@
     private static final String DESEDE_SYSTEM_PROPERTY =
             "ro.hardware.keystore_desede";
 
+    /** @hide **/
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
 
@@ -111,6 +114,7 @@
     /**
      * Installs a new instance of this provider (and the
      * {@link AndroidKeyStoreBCWorkaroundProvider}).
+     * @hide
      */
     public static void install() {
         Provider[] providers = Security.getProviders();
@@ -156,6 +160,7 @@
      * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
      *         by AndroidKeyStore provider.
      * @throws IllegalStateException if the provided primitive is not initialized.
+     * @hide
      */
     @UnsupportedAppUsage
     public static long getKeyStoreOperationHandle(Object cryptoPrimitive) {
@@ -183,6 +188,7 @@
         return ((KeyStoreCryptoOperation) spi).getOperationHandle();
     }
 
+    /** @hide **/
     @NonNull
     public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
             @NonNull String alias,
@@ -279,6 +285,7 @@
                 privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
     }
 
+    /** @hide **/
     @NonNull
     public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -300,6 +307,7 @@
         return new KeyPair(publicKey, privateKey);
     }
 
+    /** @hide **/
     @NonNull
     public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -318,6 +326,7 @@
         return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
     }
 
+    /** @hide **/
     @NonNull
     public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -357,6 +366,7 @@
         return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
     }
 
+    /** @hide **/
     @NonNull
     public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
             @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
@@ -390,7 +400,9 @@
      *
      * <p>Note: the returned {@code KeyStore} is already initialized/loaded. Thus, there is
      * no need to invoke {@code load} on it.
+     * @hide
      */
+    @SystemApi
     @NonNull
     public static java.security.KeyStore getKeyStoreForUid(int uid)
             throws KeyStoreException, NoSuchProviderException {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index e3f43ef..6df3b8c 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -19,6 +19,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
@@ -808,10 +809,14 @@
         /**
          * Sets the UID which will own the key.
          *
+         * Such cross-UID access is permitted to a few system UIDs and only to a few other UIDs
+         * (e.g., Wi-Fi, VPN) all of which are system.
+         *
          * @param uid UID or {@code -1} for the UID of the current process.
          *
          * @hide
          */
+        @SystemApi
         @NonNull
         public Builder setUid(int uid) {
             mUid = uid;
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2eef274..39a7e25 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -435,7 +435,7 @@
      * {@link SecurityException} if the location permissions were not sufficient to use the
      * specified provider.
      *
-     * @param provider the name of the provider
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @return true if the provider exists and is enabled
      *
      * @throws IllegalArgumentException if provider is null
@@ -453,7 +453,7 @@
      * {@link SecurityException} if the location permissions were not sufficient to use the
      * specified provider.
      *
-     * @param provider the name of the provider
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @param userHandle the user to query
      * @return true if the provider exists and is enabled
      *
@@ -477,8 +477,8 @@
      * functions as a best effort. It should not be relied on in any meaningful sense as providers
      * may no longer be enabled or disabled by clients.
      *
-     * @param provider the name of the provider
-     * @param enabled true to enable the provider. false to disable the provider
+     * @param provider a provider listed by {@link #getAllProviders()}
+     * @param enabled whether to enable or disable the provider
      * @param userHandle the user to set
      * @return true if the value was set, false otherwise
      *
@@ -534,7 +534,7 @@
      * will always attempt to return a current location, but will potentially use additional power
      * in the course of the attempt as compared to this method.
      *
-     * @param provider the name of the provider
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @return the last known location for the given provider, or null if not available
      * @throws SecurityException if no suitable permission is present
      * @throws IllegalArgumentException if provider is null or doesn't exist
@@ -587,7 +587,7 @@
      * determine a valid location fix more often than while in the foreground. Background
      * applications may be throttled in their location accesses to some degree.
      *
-     * @param provider           the name of the provider with which to register
+     * @param provider           a provider listed by {@link #getAllProviders()}
      * @param cancellationSignal an optional signal that allows for cancelling this call
      * @param executor           the callback will take place on this {@link Executor}
      * @param consumer           the callback invoked with either a {@link Location} or null
@@ -667,7 +667,7 @@
      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for
      * more detail on how to use this method.
      *
-     * @param provider the name of the provider with which to register
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @param listener the listener to receive location updates
      * @param looper   the looper handling listener callbacks, or null to use the looper of the
      *                 calling thread
@@ -729,7 +729,7 @@
      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
      * on how to use this method.
      *
-     * @param provider      the name of the provider with which to register
+     * @param provider      a provider listed by {@link #getAllProviders()}
      * @param pendingIntent the pending intent to send location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
@@ -829,10 +829,10 @@
      *
      * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
      *
-     * @param provider the name of the provider with which to register
-     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param provider     a provider listed by {@link #getAllProviders()}
+     * @param minTimeMs    minimum time interval between location updates in milliseconds
      * @param minDistanceM minimum distance between location updates in meters
-     * @param listener the listener to receive location updates
+     * @param listener     the listener to receive location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
@@ -857,12 +857,12 @@
      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
      * for more detail on how this method works.
      *
-     * @param provider the name of the provider with which to register
-     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param provider     a provider listed by {@link #getAllProviders()}
+     * @param minTimeMs    minimum time interval between location updates in milliseconds
      * @param minDistanceM minimum distance between location updates in meters
-     * @param listener the listener to receive location updates
-     * @param looper the looper handling listener callbacks, or null to use the looper of the
-     *               calling thread
+     * @param listener     the listener to receive location updates
+     * @param looper       the looper handling listener callbacks, or null to use the looper of the
+     *                     calling thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
@@ -886,11 +886,11 @@
      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
      * for more detail on how this method works.
      *
-     * @param provider the name of the provider with which to register
-     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param provider     a provider listed by {@link #getAllProviders()}
+     * @param minTimeMs    minimum time interval between location updates in milliseconds
      * @param minDistanceM minimum distance between location updates in meters
-     * @param executor the executor handling listener callbacks
-     * @param listener the listener to receive location updates
+     * @param executor     the executor handling listener callbacks
+     * @param listener     the listener to receive location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if executor is null
@@ -980,9 +980,9 @@
      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
      * for more detail on how this method works.
      *
-     * @param provider the name of the provider with which to register
-     * @param minTimeMs minimum time interval between location updates in milliseconds
-     * @param minDistanceM minimum distance between location updates in meters
+     * @param provider      a provider listed by {@link #getAllProviders()}
+     * @param minTimeMs     minimum time interval between location updates in milliseconds
+     * @param minDistanceM  minimum distance between location updates in meters
      * @param pendingIntent the pending intent to send location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
@@ -1317,7 +1317,7 @@
      * Returns the information about the location provider with the given name, or null if no
      * provider exists by that name.
      *
-     * @param provider the provider name
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @return location provider information, or null if provider does not exist
      *
      * @throws IllegalArgumentException if provider is null
@@ -1374,7 +1374,7 @@
      * Sends additional commands to a location provider. Can be used to support provider specific
      * extensions to the Location Manager API.
      *
-     * @param provider name of the location provider
+     * @param provider a provider listed by {@link #getAllProviders()}
      * @param command  name of the command to send to the provider
      * @param extras   optional arguments for the command, or null
      * @return true always, the return value may be ignored
@@ -1963,23 +1963,21 @@
     /**
      * No-op method to keep backward-compatibility.
      *
-     * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead.
-     * @removed
+     * @deprecated Use {@link #addNmeaListener} instead.
      */
     @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+    public boolean addNmeaListener(@NonNull GpsStatus.NmeaListener listener) {
         return false;
     }
 
     /**
      * No-op method to keep backward-compatibility.
      *
-     * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
-     * @removed
+     * @deprecated Use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
      */
     @Deprecated
-    public void removeNmeaListener(GpsStatus.NmeaListener listener) {}
+    public void removeNmeaListener(@NonNull GpsStatus.NmeaListener listener) {}
 
     /**
      * Adds an NMEA listener.
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 66764c7..d8fd1ff 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -24,7 +24,7 @@
  */
 oneway interface IMediaRoute2Provider {
     void setClient(IMediaRoute2ProviderClient client);
-    void selectRoute(String packageName, String id);
+    void requestSelectRoute(String packageName, String id, int seq);
     void unselectRoute(String packageName, String id);
     void notifyControlRequestSent(String id, in Intent request);
     void requestSetVolume(String id, int volume);
diff --git a/media/java/android/media/IMediaRouter2Client.aidl b/media/java/android/media/IMediaRouter2Client.aidl
index 72c33f99..b04af7d 100644
--- a/media/java/android/media/IMediaRouter2Client.aidl
+++ b/media/java/android/media/IMediaRouter2Client.aidl
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.media.MediaRoute2Info;
+import android.os.Bundle;
 
 /**
  * @hide
@@ -26,4 +27,5 @@
     void notifyRoutesAdded(in List<MediaRoute2Info> routes);
     void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
     void notifyRoutesChanged(in List<MediaRoute2Info> routes);
+    void notifyRouteSelected(in MediaRoute2Info route, int reason, in Bundle controlHints);
 }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 7b7a34e..ced8615 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -54,7 +54,7 @@
      * @param client the client that changes it's selected route
      * @param route the route to be selected
      */
-    void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
+    void requestSelectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
     void setControlCategories2(IMediaRouter2Client client, in List<String> categories);
 
     void registerManager(IMediaRouter2Manager manager, String packageName);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 457ccb7..2380077 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -274,7 +274,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mId);
         dest.writeString(mProviderId);
         dest.writeString(mName);
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 8541f32..4f203de 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -95,8 +95,8 @@
      * Gets the route for the given route id or null if no matching route exists.
      */
     @Nullable
-    public MediaRoute2Info getRoute(String routeId) {
-        return mRoutes.get(routeId);
+    public MediaRoute2Info getRoute(@NonNull String routeId) {
+        return mRoutes.get(Objects.requireNonNull(routeId, "routeId must not be null"));
     }
 
     /**
@@ -113,7 +113,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mUniqueId);
         dest.writeTypedArrayMap(mRoutes, flags);
     }
@@ -155,6 +155,7 @@
          * </p>
          * @hide
          */
+        @NonNull
         public Builder setUniqueId(@Nullable String uniqueId) {
             if (TextUtils.equals(mUniqueId, uniqueId)) {
                 return this;
@@ -174,6 +175,7 @@
         /**
          * Adds a route to the provider
          */
+        @NonNull
         public Builder addRoute(@NonNull MediaRoute2Info route) {
             Objects.requireNonNull(route, "route must not be null");
 
@@ -192,6 +194,7 @@
         /**
          * Adds a list of routes to the provider
          */
+        @NonNull
         public Builder addRoutes(@NonNull Collection<MediaRoute2Info> routes) {
             Objects.requireNonNull(routes, "routes must not be null");
 
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 5f5d200..386d2dc 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -128,7 +128,9 @@
         }
 
         @Override
-        public void selectRoute(String packageName, String id) {
+        public void requestSelectRoute(String packageName, String id, int seq) {
+            // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
+            // use the sequence number here properly.
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
                     MediaRoute2ProviderService.this, packageName, id));
         }
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 86fa9db..74d26f0 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -103,6 +104,8 @@
 
     private MediaRoute2Info mSelectedRoute;
     @GuardedBy("sLock")
+    private MediaRoute2Info mSelectingRoute;
+    @GuardedBy("sLock")
     private Client mClient;
 
     final Handler mHandler;
@@ -250,24 +253,28 @@
     }
 
     /**
-     * Selects the specified route.
+     * Request to select the specified route. When the route is selected,
+     * {@link Callback#onRouteSelected(MediaRoute2Info, int, Bundle)} will be called.
      *
      * @param route the route to select
      */
-    //TODO: add a parameter for category (e.g. mirroring/casting)
-    public void selectRoute(@NonNull MediaRoute2Info route) {
+    public void requestSelectRoute(@NonNull MediaRoute2Info route) {
         Objects.requireNonNull(route, "route must not be null");
 
         Client client;
         synchronized (sLock) {
-            mSelectedRoute = route;
+            if (mSelectingRoute == route) {
+                Log.w(TAG, "The route selection request is already sent.");
+                return;
+            }
+            mSelectingRoute = route;
             client = mClient;
         }
         if (client != null) {
             try {
-                mMediaRouterService.selectRoute2(client, route);
+                mMediaRouterService.requestSelectRoute2(client, route);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to select route.", ex);
+                Log.e(TAG, "Unable to request to select route.", ex);
             }
         }
     }
@@ -443,6 +450,22 @@
         }
     }
 
+    void selectRouteOnHandler(MediaRoute2Info route, int reason, Bundle controlHints) {
+        synchronized (sLock) {
+            if (reason == SELECT_REASON_USER_SELECTED) {
+                if (mSelectingRoute == null
+                        || !TextUtils.equals(mSelectingRoute.getUniqueId(), route.getUniqueId())) {
+                    Log.w(TAG, "Ignoring invalid or outdated notifyRouteSelected call. "
+                            + "selectingRoute=" + mSelectingRoute + " route=" + route);
+                    return;
+                }
+            }
+            mSelectingRoute = null;
+        }
+        mSelectedRoute = route;
+        notifyRouteSelected(route, reason, controlHints);
+    }
+
     private void refreshFilteredRoutes() {
         List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
 
@@ -475,12 +498,17 @@
         }
     }
 
+    private void notifyRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+        for (CallbackRecord record: mCallbackRecords) {
+            record.mExecutor.execute(
+                    () -> record.mCallback.onRouteSelected(route, reason, controlHints));
+        }
+    }
+
     /**
      * Interface for receiving events about media routing changes.
      */
     public static class Callback {
-        //TODO: clean up these callbacks
-
         /**
          * Called when routes are added.
          * @param routes the list of routes that have been added. It's never empty.
@@ -505,20 +533,19 @@
          */
         public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
 
-        // TODO: Make this callback be called when we add requestSelectRoute().
         /**
          * Called when a route is selected. Exactly one route can be selected at a time.
          * @param route the selected route.
          * @param reason the reason why the route is selected.
-         * @param connectionHints An optional bundle of provider-specific arguments which may be
-         *                        used to control the selected route. Can be empty.
+         * @param controlHints An optional bundle of provider-specific arguments which may be
+         *                     used to control the selected route. Can be empty.
          * @see #SELECT_REASON_UNKNOWN
          * @see #SELECT_REASON_USER_SELECTED
          * @see #SELECT_REASON_FALLBACK
          * @see #getSelectedRoute()
          */
         public void onRouteSelected(@NonNull MediaRoute2Info route, @SelectReason int reason,
-                @NonNull Bundle connectionHints) {}
+                @NonNull Bundle controlHints) {}
     }
 
     final class CallbackRecord {
@@ -560,5 +587,12 @@
             mHandler.sendMessage(obtainMessage(MediaRouter2::changeRoutesOnHandler,
                     MediaRouter2.this, routes));
         }
+
+        @Override
+        public void notifyRouteSelected(MediaRoute2Info route, int reason,
+                Bundle controlHints) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2::selectRouteOnHandler,
+                    MediaRouter2.this, route, reason, controlHints));
+        }
     }
 }
diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt
index be3531d..8d4e900 100644
--- a/native/android/libandroid_net.map.txt
+++ b/native/android/libandroid_net.map.txt
@@ -1,15 +1,19 @@
-# They are also all available to vendor code.
+# The following symbols marked with # llndk are available to vendor code.
+# Unlike other VNDK libraries where keeping backwards compatibility is required
+# only within a platform release, these symbols need much longer suppport
+# because the same LLNDK library serves for both system and vendor partition
+# which might be a few years old.
 LIBANDROID_NET {
   global:
     # These functions have been part of the NDK since API 24.
-    android_getaddrinfofornetwork; # vndk
-    android_setsocknetwork; # vndk
-    android_setprocnetwork; # vndk
+    android_getaddrinfofornetwork; # llndk
+    android_setsocknetwork; # llndk
+    android_setprocnetwork; # llndk
     # These functions have been part of the NDK since API 29.
-    android_res_cancel; # vndk
-    android_res_nquery; # vndk
-    android_res_nresult; # vndk
-    android_res_nsend; # vndk
+    android_res_cancel; # llndk
+    android_res_nquery; # llndk
+    android_res_nresult; # llndk
+    android_res_nsend; # llndk
   local:
     *;
 };
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
new file mode 100644
index 0000000..f8bfeec
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.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.systemui.car;
+
+import android.car.Car;
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Provides a common connection to the car service that can be shared. */
+@Singleton
+public class CarServiceProvider {
+
+    private final Context mContext;
+    private final List<CarServiceOnConnectedListener> mListeners = new ArrayList<>();
+    private Car mCar;
+
+    @Inject
+    public CarServiceProvider(Context context) {
+        mContext = context;
+        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                (car, ready) -> {
+                    mCar = car;
+
+                    synchronized (mListeners) {
+                        for (CarServiceOnConnectedListener listener : mListeners) {
+                            if (ready) {
+                                listener.onConnected(mCar);
+                            }
+                        }
+                    }
+                });
+    }
+
+    /**
+     * Let's other components hook into the connection to the car service. If we're already
+     * connected to the car service, the callback is immediately triggered.
+     */
+    public void addListener(CarServiceOnConnectedListener listener) {
+        if (mCar.isConnected()) {
+            listener.onConnected(mCar);
+        }
+        mListeners.add(listener);
+    }
+
+    /**
+     * Listener which is triggered when Car Service is connected.
+     */
+    public interface CarServiceOnConnectedListener {
+        /** This will be called when the car service has successfully been connected. */
+        void onConnected(Car car);
+    }
+}
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 af92767..08ab492 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -37,6 +37,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -54,10 +55,12 @@
     private final WindowManager mWindowManager;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final CommandQueue mCommandQueue;
-    private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener;
+    private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListenerLazy;
     private final Handler mMainHandler;
-    private final Lazy<KeyguardStateController> mKeyguardStateController;
-    private final Lazy<NavigationBarController> mNavigationBarController;
+    private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
+    private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
+    private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy;
 
     private IStatusBarService mBarService;
     private ActivityManagerWrapper mActivityManagerWrapper;
@@ -67,10 +70,12 @@
     private boolean mBottomNavBarVisible;
 
     // Nav bar views.
-    private ViewGroup mNavigationBarWindow;
+    private ViewGroup mTopNavigationBarWindow;
+    private ViewGroup mBottomNavigationBarWindow;
     private ViewGroup mLeftNavigationBarWindow;
     private ViewGroup mRightNavigationBarWindow;
-    private CarNavigationBarView mNavigationBarView;
+    private CarNavigationBarView mTopNavigationBarView;
+    private CarNavigationBarView mBottomNavigationBarView;
     private CarNavigationBarView mLeftNavigationBarView;
     private CarNavigationBarView mRightNavigationBarView;
 
@@ -84,19 +89,23 @@
             WindowManager windowManager,
             DeviceProvisionedController deviceProvisionedController,
             CommandQueue commandQueue,
-            Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener,
+            Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListenerLazy,
             @MainHandler Handler mainHandler,
-            Lazy<KeyguardStateController> keyguardStateController,
-            Lazy<NavigationBarController> navigationBarController) {
+            Lazy<KeyguardStateController> keyguardStateControllerLazy,
+            Lazy<NavigationBarController> navigationBarControllerLazy,
+            SuperStatusBarViewFactory superStatusBarViewFactory,
+            Lazy<CarFacetButtonController> carFacetButtonControllerLazy) {
         super(context);
         mCarNavigationBarController = carNavigationBarController;
         mWindowManager = windowManager;
         mDeviceProvisionedController = deviceProvisionedController;
         mCommandQueue = commandQueue;
-        mFacetButtonTaskStackListener = facetButtonTaskStackListener;
+        mFacetButtonTaskStackListenerLazy = facetButtonTaskStackListenerLazy;
         mMainHandler = mainHandler;
-        mKeyguardStateController = keyguardStateController;
-        mNavigationBarController = navigationBarController;
+        mKeyguardStateControllerLazy = keyguardStateControllerLazy;
+        mNavigationBarControllerLazy = navigationBarControllerLazy;
+        mSuperStatusBarViewFactory = superStatusBarViewFactory;
+        mCarFacetButtonControllerLazy = carFacetButtonControllerLazy;
     }
 
     @Override
@@ -137,7 +146,7 @@
         createNavigationBar(result);
 
         mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
-        mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get());
+        mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListenerLazy.get());
 
         mCarNavigationBarController.connectToHvac();
     }
@@ -158,10 +167,16 @@
         // remove and reattach all hvac components such that we don't keep a reference to unused
         // ui elements
         mCarNavigationBarController.removeAllFromHvac();
+        mCarFacetButtonControllerLazy.get().removeAll();
 
-        if (mNavigationBarWindow != null) {
-            mNavigationBarWindow.removeAllViews();
-            mNavigationBarView = null;
+        if (mTopNavigationBarWindow != null) {
+            mTopNavigationBarWindow.removeAllViews();
+            mTopNavigationBarView = null;
+        }
+
+        if (mBottomNavigationBarWindow != null) {
+            mBottomNavigationBarWindow.removeAllViews();
+            mBottomNavigationBarView = null;
         }
 
         if (mLeftNavigationBarWindow != null) {
@@ -177,8 +192,8 @@
         buildNavBarContent();
         // If the UI was rebuilt (day/night change) while the keyguard was up we need to
         // correctly respect that state.
-        if (mKeyguardStateController.get().isShowing()) {
-            updateNavBarForKeyguardContent();
+        if (mKeyguardStateControllerLazy.get().isShowing()) {
+            mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
         }
     }
 
@@ -196,20 +211,28 @@
 
         // There has been a car customized nav bar on the default display, so just create nav bars
         // on external displays.
-        mNavigationBarController.get().createNavigationBars(/* includeDefaultDisplay= */ false,
+        mNavigationBarControllerLazy.get().createNavigationBars(/* includeDefaultDisplay= */ false,
                 result);
     }
 
     private void buildNavBarWindows() {
-        mNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
+        mTopNavigationBarWindow = mSuperStatusBarViewFactory
+                .getStatusBarWindowView()
+                .findViewById(R.id.car_top_navigation_bar_container);
+        mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
         mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
         mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
     }
 
     private void buildNavBarContent() {
-        mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
-        if (mNavigationBarView != null) {
-            mNavigationBarWindow.addView(mNavigationBarView);
+        mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
+        if (mTopNavigationBarView != null) {
+            mTopNavigationBarWindow.addView(mTopNavigationBarView);
+        }
+
+        mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
+        if (mBottomNavigationBarView != null) {
+            mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
         }
 
         mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser);
@@ -224,7 +247,7 @@
     }
 
     private void attachNavBarWindows() {
-        if (mNavigationBarWindow != null && !mBottomNavBarVisible) {
+        if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
             mBottomNavBarVisible = true;
 
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -237,7 +260,7 @@
                     PixelFormat.TRANSLUCENT);
             lp.setTitle("CarNavigationBar");
             lp.windowAnimations = 0;
-            mWindowManager.addView(mNavigationBarWindow, lp);
+            mWindowManager.addView(mBottomNavigationBarWindow, lp);
         }
 
         if (mLeftNavigationBarWindow != null) {
@@ -297,23 +320,11 @@
                 isKeyboardVisible ? View.GONE : View.VISIBLE);
     }
 
-    private void updateNavBarForKeyguardContent() {
-        if (mNavigationBarView != null) {
-            mNavigationBarView.showKeyguardButtons();
-        }
-        if (mLeftNavigationBarView != null) {
-            mLeftNavigationBarView.showKeyguardButtons();
-        }
-        if (mRightNavigationBarView != null) {
-            mRightNavigationBarView.showKeyguardButtons();
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("  mTaskStackListener=");
-        pw.println(mFacetButtonTaskStackListener.get());
-        pw.print("  mNavigationBarView=");
-        pw.println(mNavigationBarView);
+        pw.println(mFacetButtonTaskStackListenerLazy.get());
+        pw.print("  mBottomNavigationBarView=");
+        pw.println(mBottomNavigationBarView);
     }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
index 6bed69b..6f28843 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
@@ -24,8 +24,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.car.hvac.HvacController;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
+import com.android.systemui.navigationbar.car.hvac.HvacController;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -38,6 +37,7 @@
 
     private final Context mContext;
     private final NavigationBarViewFactory mNavigationBarViewFactory;
+    private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy;
     private final Lazy<HvacController> mHvacControllerLazy;
 
     private boolean mShowBottom;
@@ -58,9 +58,11 @@
     @Inject
     public CarNavigationBarController(Context context,
             NavigationBarViewFactory navigationBarViewFactory,
+            Lazy<CarFacetButtonController> carFacetButtonControllerLazy,
             Lazy<HvacController> hvacControllerLazy) {
         mContext = context;
         mNavigationBarViewFactory = navigationBarViewFactory;
+        mCarFacetButtonControllerLazy = carFacetButtonControllerLazy;
         mHvacControllerLazy = hvacControllerLazy;
 
         // Read configuration.
@@ -129,9 +131,7 @@
     @NonNull
     public CarNavigationBarView getTopBar(boolean isSetUp) {
         mTopView = mNavigationBarViewFactory.getTopBar(isSetUp);
-        mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
-        mTopView.setNotificationsPanelController(mNotificationsShadeController);
-        addTemperatureViewToController(mTopView);
+        setupBar(mTopView, mTopBarTouchListener, mNotificationsShadeController);
         return mTopView;
     }
 
@@ -143,9 +143,7 @@
         }
 
         mBottomView = mNavigationBarViewFactory.getBottomBar(isSetUp);
-        mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
-        mBottomView.setNotificationsPanelController(mNotificationsShadeController);
-        addTemperatureViewToController(mBottomView);
+        setupBar(mBottomView, mBottomBarTouchListener, mNotificationsShadeController);
         return mBottomView;
     }
 
@@ -157,9 +155,7 @@
         }
 
         mLeftView = mNavigationBarViewFactory.getLeftBar(isSetUp);
-        mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
-        mLeftView.setNotificationsPanelController(mNotificationsShadeController);
-        addTemperatureViewToController(mLeftView);
+        setupBar(mLeftView, mLeftBarTouchListener, mNotificationsShadeController);
         return mLeftView;
     }
 
@@ -171,12 +167,18 @@
         }
 
         mRightView = mNavigationBarViewFactory.getRightBar(isSetUp);
-        mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
-        mRightView.setNotificationsPanelController(mNotificationsShadeController);
-        addTemperatureViewToController(mRightView);
+        setupBar(mRightView, mRightBarTouchListener, mNotificationsShadeController);
         return mRightView;
     }
 
+    private void setupBar(CarNavigationBarView view, View.OnTouchListener statusBarTouchListener,
+            NotificationsShadeController notifShadeController) {
+        view.setStatusBarWindowTouchListener(statusBarTouchListener);
+        view.setNotificationsPanelController(notifShadeController);
+        mCarFacetButtonControllerLazy.get().addAllFacetButtons(view);
+        mHvacControllerLazy.get().addTemperatureViewToController(view);
+    }
+
     /** Sets a touch listener for the top navigation bar. */
     public void registerTopBarTouchListener(View.OnTouchListener listener) {
         mTopBarTouchListener = listener;
@@ -290,17 +292,6 @@
         void togglePanel();
     }
 
-    private void addTemperatureViewToController(View v) {
-        if (v instanceof TemperatureView) {
-            mHvacControllerLazy.get().addHvacTextView((TemperatureView) v);
-        } else if (v instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) v;
-            for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                addTemperatureViewToController(viewGroup.getChildAt(i));
-            }
-        }
-    }
-
     private void checkAllBars(boolean isSetUp) {
         mTopView = getTopBar(isSetUp);
         mBottomView = getBottomBar(isSetUp);
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java
similarity index 79%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
rename to packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java
index 41914d2..af2cb0a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
 
 import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
 import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
 
 import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
 import android.car.VehicleUnit;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
-import android.content.Context;
-import android.os.Handler;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.car.CarServiceProvider;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -37,19 +38,18 @@
 import java.util.Objects;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * Manages the connection to the Car service and delegates value changes to the registered
  * {@link TemperatureView}s
  */
+@Singleton
 public class HvacController {
-
     public static final String TAG = "HvacController";
-    public static final int BIND_TO_HVAC_RETRY_DELAY = 5000;
 
-    private Context mContext;
-    private Handler mHandler;
-    private Car mCar;
+    private final CarServiceProvider mCarServiceProvider;
+
     private CarHvacManager mHvacManager;
     private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
 
@@ -85,22 +85,20 @@
         }
     };
 
-    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
-        if (!ready) {
-            return;
-        }
-        try {
-            mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
-            mHvacManager.registerCallback(mHardwareCallback);
-            initComponents();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to correctly connect to HVAC", e);
-        }
-    };
+    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
+            car -> {
+                try {
+                    mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
+                    mHvacManager.registerCallback(mHardwareCallback);
+                    initComponents();
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to correctly connect to HVAC", e);
+                }
+            };
 
     @Inject
-    public HvacController(Context context) {
-        mContext = context;
+    public HvacController(CarServiceProvider carServiceProvider) {
+        mCarServiceProvider = carServiceProvider;
     }
 
     /**
@@ -108,9 +106,7 @@
      * ({@link CarHvacManager}) will happen on the same thread this method was called from.
      */
     public void connectToCarService() {
-        mHandler = new Handler();
-        mCar = Car.createCar(mContext, /* handler= */ mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
-                mCarServiceLifecycleListener);
+        mCarServiceProvider.addListener(mCarServiceLifecycleListener);
     }
 
     /**
@@ -172,6 +168,21 @@
     }
 
     /**
+     * Iterate through a view, looking for {@link TemperatureView} instances and add them to the
+     * controller if found.
+     */
+    public void addTemperatureViewToController(View v) {
+        if (v instanceof TemperatureView) {
+            addHvacTextView((TemperatureView) v);
+        } else if (v instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) v;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                addTemperatureViewToController(viewGroup.getChildAt(i));
+            }
+        }
+    }
+
+    /**
      * Key for storing {@link TemperatureView}s in a hash map
      */
     private static class HvacKey {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java
similarity index 95%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
rename to packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java
index 17ef3c0..ad4fcd9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java
similarity index 93%
rename from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
rename to packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java
index c17da18..963f318 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
 
 /**
  * Interface for Views that display temperature HVAC properties
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 78ac960..10527b2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -57,15 +57,14 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
-import com.android.systemui.CarSystemUIFactory;
 import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.fragments.FragmentHostManager;
@@ -73,9 +72,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.navigationbar.car.CarFacetButtonController;
 import com.android.systemui.navigationbar.car.CarNavigationBarController;
-import com.android.systemui.navigationbar.car.CarNavigationBarView;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.car.CarQSFragment;
@@ -164,20 +161,20 @@
     private float mBackgroundAlphaDiff;
     private float mInitialBackgroundAlpha;
 
+    private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy;
     private FullscreenUserSwitcher mFullscreenUserSwitcher;
 
     private CarBatteryController mCarBatteryController;
     private BatteryMeterView mBatteryMeterView;
     private Drawable mNotificationPanelBackground;
 
-    private ViewGroup mTopNavigationBarContainer;
-    private CarNavigationBarView mTopNavigationBarView;
-
     private final Object mQueueLock = new Object();
     private final CarNavigationBarController mCarNavigationBarController;
-    private CarFacetButtonController mCarFacetButtonController;
+    private final Lazy<DrivingStateHelper> mDrivingStateHelperLazy;
+    private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
+    private final CarServiceProvider mCarServiceProvider;
+
     private DeviceProvisionedController mDeviceProvisionedController;
-    private boolean mDeviceIsSetUpForUser = true;
     private DrivingStateHelper mDrivingStateHelper;
     private PowerManagerHelper mPowerManagerHelper;
     private FlingAnimationUtils mFlingAnimationUtils;
@@ -311,6 +308,10 @@
             ViewMediatorCallback viewMediatorCallback,
             DismissCallbackRegistry dismissCallbackRegistry,
             /* Car Settings injected components. */
+            CarServiceProvider carServiceProvider,
+            Lazy<DrivingStateHelper> drivingStateHelperLazy,
+            Lazy<PowerManagerHelper> powerManagerHelperLazy,
+            Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
             CarNavigationBarController carNavigationBarController) {
         super(
                 context,
@@ -384,16 +385,16 @@
                 viewMediatorCallback,
                 dismissCallbackRegistry);
         mScrimController = scrimController;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mCarServiceProvider = carServiceProvider;
+        mDrivingStateHelperLazy = drivingStateHelperLazy;
+        mPowerManagerHelperLazy = powerManagerHelperLazy;
+        mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
         mCarNavigationBarController = carNavigationBarController;
     }
 
     @Override
     public void start() {
-        // get the provisioned state before calling the parent class since it's that flow that
-        // builds the nav bar
-        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
-        mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup();
-
         // Need to initialize screen lifecycle before calling super.start - before switcher is
         // created.
         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -431,52 +432,20 @@
         createBatteryController();
         mCarBatteryController.startListening();
 
-        mDeviceProvisionedController.addCallback(
-                new DeviceProvisionedController.DeviceProvisionedListener() {
-                    @Override
-                    public void onUserSetupChanged() {
-                        mHandler.post(() -> resetSystemBarsIfNecessary());
-                    }
-
-                    @Override
-                    public void onUserSwitched() {
-                        mHandler.post(() -> resetSystemBarsIfNecessary());
-                    }
-                });
-
         // Used by onDrivingStateChanged and it can be called inside
         // DrivingStateHelper.connectToCarService()
         mSwitchToGuestTimer = new SwitchToGuestTimer(mContext);
 
         // Register a listener for driving state changes.
-        mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged);
+        mDrivingStateHelper = mDrivingStateHelperLazy.get();
+        mDrivingStateHelper.setCarDrivingStateEventListener(this::onDrivingStateChanged);
         mDrivingStateHelper.connectToCarService();
 
-        mPowerManagerHelper = new PowerManagerHelper(mContext, mCarPowerStateListener);
+        mPowerManagerHelper = mPowerManagerHelperLazy.get();
+        mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener);
         mPowerManagerHelper.connectToCarService();
     }
 
-    private void resetSystemBarsIfNecessary() {
-        boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-        if (mDeviceIsSetUpForUser != currentUserSetup) {
-            mDeviceIsSetUpForUser = currentUserSetup;
-            resetSystemBars();
-        }
-    }
-
-    /**
-     * Remove all content from navbars and rebuild them. Used to allow for different nav bars
-     * before and after the device is provisioned. . Also for change of density and font size.
-     */
-    private void resetSystemBars() {
-        mCarFacetButtonController.removeAll();
-
-        buildNavBarContent();
-        // CarFacetButtonController was reset therefore we need to re-add the status bar elements
-        // to the controller.
-        mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow);
-    }
-
     /**
      * Allows for showing or hiding just the navigation bars. This is indented to be used when
      * the full screen user selector is shown.
@@ -490,23 +459,22 @@
     @Override
     public boolean hideKeyguard() {
         boolean result = super.hideKeyguard();
-        mCarNavigationBarController.hideAllKeyguardButtons(mDeviceIsSetUpForUser);
+        mCarNavigationBarController.hideAllKeyguardButtons(
+                mDeviceProvisionedController.isCurrentUserSetup());
         return result;
     }
 
     @Override
     public void showKeyguard() {
         super.showKeyguard();
-        mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
+        mCarNavigationBarController.showAllKeyguardButtons(
+                mDeviceProvisionedController.isCurrentUserSetup());
     }
 
     @Override
     protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
         super.makeStatusBarView(result);
 
-        CarSystemUIFactory factory = SystemUIFactory.getInstance();
-        mCarFacetButtonController = factory.getCarDependencyComponent()
-                .getCarFacetButtonController();
         mNotificationPanelBackground = getDefaultWallpaper();
         mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
 
@@ -562,7 +530,7 @@
                 new HandleBarCloseNotificationGestureListener());
 
         mTopNavBarNotificationTouchListener = (v, event) -> {
-            if (!mDeviceIsSetUpForUser) {
+            if (!mDeviceProvisionedController.isCurrentUserSetup()) {
                 return true;
             }
             boolean consumed = openGestureDetector.onTouchEvent(event);
@@ -592,20 +560,13 @@
         });
         CarNotificationListener carNotificationListener = new CarNotificationListener();
         mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
-        // This can take time if car service is not ready up to this time.
-        // TODO(b/142808072) Refactor CarUxRestrictionManagerWrapper to allow setting
-        // CarUxRestrictionsManager later and switch to Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT.
-        Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
-                (car, ready) -> {
-                    if (!ready) {
-                        return;
-                    }
-                    CarUxRestrictionsManager carUxRestrictionsManager =
-                            (CarUxRestrictionsManager)
-                                    car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
-                    mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
-                            carUxRestrictionsManager);
-                });
+        mCarServiceProvider.addListener(car -> {
+            CarUxRestrictionsManager carUxRestrictionsManager =
+                    (CarUxRestrictionsManager)
+                            car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+            mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
+                    carUxRestrictionsManager);
+        });
 
         mNotificationDataManager = new NotificationDataManager();
         mNotificationDataManager.setOnUnseenCountUpdateListener(
@@ -614,7 +575,7 @@
                         boolean hasUnseen =
                                 mNotificationDataManager.getUnseenNotificationCount() > 0;
                         mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
-                                mDeviceIsSetUpForUser, hasUnseen);
+                                mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
                     }
                 });
 
@@ -868,14 +829,14 @@
 
     @Override
     protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
-        mTopNavigationBarContainer = mStatusBarWindow
-                .findViewById(R.id.car_top_navigation_bar_container);
-
-        buildNavBarContent();
+        registerNavBarListeners();
     }
 
-    private void buildNavBarContent() {
-        buildTopBar();
+    private void registerNavBarListeners() {
+        // In CarStatusBar, navigation bars are built by NavigationBar.java
+        // Instead, we register necessary callbacks to the navigation bar controller.
+        mCarNavigationBarController.registerTopBarTouchListener(
+                mTopNavBarNotificationTouchListener);
 
         mCarNavigationBarController.registerBottomBarTouchListener(
                 mNavBarNotificationTouchListener);
@@ -889,14 +850,6 @@
         mCarNavigationBarController.registerNotificationController(() -> togglePanel());
     }
 
-    private void buildTopBar() {
-        mTopNavigationBarContainer.removeAllViews();
-        mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
-        mCarNavigationBarController.registerTopBarTouchListener(
-                mTopNavBarNotificationTouchListener);
-        mTopNavigationBarContainer.addView(mTopNavigationBarView);
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         //When executing dump() function simultaneously, we need to serialize them
@@ -908,8 +861,6 @@
                     + "," + mStackScroller.getScrollY());
         }
 
-        pw.print("  mCarFacetButtonController=");
-        pw.println(mCarFacetButtonController);
         pw.print("  mFullscreenUserSwitcher=");
         pw.println(mFullscreenUserSwitcher);
         pw.print("  mCarBatteryController=");
@@ -974,8 +925,10 @@
         UserSwitcherController userSwitcherController =
                 Dependency.get(UserSwitcherController.class);
         if (userSwitcherController.useFullscreenUserSwitcher()) {
-            mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
-                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
+            mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get();
+            mFullscreenUserSwitcher.setStatusBar(this);
+            mFullscreenUserSwitcher.setContainer(
+                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
         } else {
             super.createUserSwitcher();
         }
@@ -1058,7 +1011,7 @@
     @Override
     public void onDensityOrFontScaleChanged() {
         super.onDensityOrFontScaleChanged();
-        resetSystemBars();
+        registerNavBarListeners();
         // Need to update the background on density changed in case the change was due to night
         // mode.
         mNotificationPanelBackground = getDefaultWallpaper();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index b9dacc0..5418ebe 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -29,6 +29,7 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -179,6 +180,10 @@
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             ViewMediatorCallback viewMediatorCallback,
             DismissCallbackRegistry dismissCallbackRegistry,
+            CarServiceProvider carServiceProvider,
+            Lazy<DrivingStateHelper> drivingStateHelperLazy,
+            Lazy<PowerManagerHelper> powerManagerHelperLazy,
+            Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
             CarNavigationBarController carNavigationBarController) {
         return new CarStatusBar(
                 context,
@@ -250,6 +255,10 @@
                 statusBarKeyguardViewManager,
                 viewMediatorCallback,
                 dismissCallbackRegistry,
+                carServiceProvider,
+                drivingStateHelperLazy,
+                powerManagerHelperLazy,
+                fullscreenUserSwitcherLazy,
                 carNavigationBarController);
     }
 }
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 ec72ee7..ec46433 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -36,15 +37,21 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainResources;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * A helper class displays an unlock dialog and receives broadcast about detecting trusted device
  * & unlocking state to show the appropriate message on the dialog.
  */
+@Singleton
 class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
     private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName();
 
     private final Context mContext;
+    private final Resources mResources;
     private final WindowManager mWindowManager;
     private final UserManager mUserManager;
     private final WindowManager.LayoutParams mParams;
@@ -60,10 +67,13 @@
     private boolean mIsDialogShowing;
     private OnHideListener mOnHideListener;
 
-    CarTrustAgentUnlockDialogHelper(Context context) {
+    @Inject
+    CarTrustAgentUnlockDialogHelper(Context context, @MainResources Resources resources,
+            UserManager userManager, WindowManager windowManager) {
         mContext = context;
-        mUserManager = mContext.getSystemService(UserManager.class);
-        mWindowManager = mContext.getSystemService(WindowManager.class);
+        mResources = resources;
+        mUserManager = userManager;
+        mWindowManager = windowManager;
         mParams = createLayoutParams();
         mFilter = getIntentFilter();
 
@@ -125,7 +135,7 @@
      * @param listener listener that listens to dialog hide
      */
     void showUnlockDialogAfterDelay(int uid, OnHideListener listener) {
-        long delayMillis = mContext.getResources().getInteger(R.integer.unlock_dialog_delay_ms);
+        long delayMillis = mResources.getInteger(R.integer.unlock_dialog_delay_ms);
         showUnlockDialogAfterDelay(uid, delayMillis, listener);
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
index cd87e78..60934ab 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
@@ -17,31 +17,43 @@
 package com.android.systemui.statusbar.car;
 
 import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarDrivingStateManager;
 import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener;
-import android.content.Context;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 
+import com.android.systemui.car.CarServiceProvider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Helper class for connecting to the {@link CarDrivingStateManager} and listening for driving state
  * changes.
  */
+@Singleton
 public class DrivingStateHelper {
     public static final String TAG = "DrivingStateHelper";
 
-    private final Context mContext;
+    private final CarServiceProvider mCarServiceProvider;
+
     private CarDrivingStateManager mDrivingStateManager;
-    private Car mCar;
     private CarDrivingStateEventListener mDrivingStateHandler;
 
-    public DrivingStateHelper(Context context,
-            @NonNull CarDrivingStateEventListener drivingStateHandler) {
-        mContext = context;
-        mDrivingStateHandler = drivingStateHandler;
+    @Inject
+    public DrivingStateHelper(CarServiceProvider carServiceProvider) {
+        mCarServiceProvider = carServiceProvider;
+    }
+
+    /**
+     * Sets the {@link CarDrivingStateEventListener}. Should be set before calling {@link
+     * #connectToCarService()}.
+     */
+    public void setCarDrivingStateEventListener(
+            @NonNull CarDrivingStateEventListener carDrivingStateEventListener) {
+        mDrivingStateHandler = carDrivingStateEventListener;
     }
 
     /**
@@ -64,25 +76,22 @@
      * Establishes connection with the Car service.
      */
     public void connectToCarService() {
-        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
-                mCarServiceLifecycleListener);
+        mCarServiceProvider.addListener(mCarServiceLifecycleListener);
     }
 
-    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
-        if (!ready) {
-            return;
-        }
-        logD("Car Service connected");
-        mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
-                Car.CAR_DRIVING_STATE_SERVICE);
-        if (mDrivingStateManager != null) {
-            mDrivingStateManager.registerListener(mDrivingStateHandler);
-            mDrivingStateHandler.onDrivingStateChanged(
-                    mDrivingStateManager.getCurrentCarDrivingState());
-        } else {
-            Log.e(TAG, "CarDrivingStateService service not available");
-        }
-    };
+    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
+            car -> {
+                logD("Car Service connected");
+                mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
+                        Car.CAR_DRIVING_STATE_SERVICE);
+                if (mDrivingStateManager != null) {
+                    mDrivingStateManager.registerListener(mDrivingStateHandler);
+                    mDrivingStateHandler.onDrivingStateChanged(
+                            mDrivingStateManager.getCurrentCarDrivingState());
+                } else {
+                    Log.e(TAG, "CarDrivingStateService service not available");
+                }
+            };
 
     private void logD(String message) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 31aced0..b188dc3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
@@ -35,24 +36,34 @@
 import androidx.recyclerview.widget.GridLayoutManager;
 
 import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
 import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Manages the fullscreen user switcher.
  */
+@Singleton
 public class FullscreenUserSwitcher {
     private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
     // Because user 0 is headless, user count for single user is 2
     private static final int NUMBER_OF_BACKGROUND_USERS = 1;
-    private final UserGridRecyclerView mUserGridView;
-    private final View mParent;
-    private final int mShortAnimDuration;
-    private final CarStatusBar mStatusBar;
+
     private final Context mContext;
+    private final Resources mResources;
     private final UserManager mUserManager;
+    private final CarServiceProvider mCarServiceProvider;
+    private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+    private final int mShortAnimDuration;
+
+    private CarStatusBar mStatusBar;
+    private View mParent;
+    private UserGridRecyclerView mUserGridView;
     private CarTrustAgentEnrollmentManager mEnrollmentManager;
-    private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
     private UserGridRecyclerView.UserRecord mSelectedUser;
     private CarUserManagerHelper mCarUserManagerHelper;
     private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
@@ -65,37 +76,46 @@
             mContext.unregisterReceiver(mUserUnlockReceiver);
         }
     };
-    private final Car mCar;
 
-    public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
-        mStatusBar = statusBar;
-        mParent = containerStub.inflate();
+    @Inject
+    public FullscreenUserSwitcher(
+            Context context,
+            @MainResources Resources resources,
+            UserManager userManager,
+            CarServiceProvider carServiceProvider,
+            CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) {
         mContext = context;
+        mResources = resources;
+        mUserManager = userManager;
+        mCarServiceProvider = carServiceProvider;
+        mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
+
+        mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
+    }
+
+    /** Sets the status bar which controls the keyguard. */
+    public void setStatusBar(CarStatusBar statusBar) {
+        mStatusBar = statusBar;
+    }
+
+    /** Sets the {@link ViewStub} to show the user switcher. */
+    public void setContainer(ViewStub containerStub) {
+        mParent = containerStub.inflate();
 
         View container = mParent.findViewById(R.id.container);
 
         // Initialize user grid.
         mUserGridView = container.findViewById(R.id.user_grid);
-        GridLayoutManager layoutManager = new GridLayoutManager(context,
-                context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+        GridLayoutManager layoutManager = new GridLayoutManager(mContext,
+                mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
         mUserGridView.setLayoutManager(layoutManager);
         mUserGridView.buildAdapter();
         mUserGridView.setUserSelectionListener(this::onUserSelected);
-        mCarUserManagerHelper = new CarUserManagerHelper(context);
-        mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext);
-        mUserManager = mContext.getSystemService(UserManager.class);
+        mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+        mCarServiceProvider.addListener(
+                car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
+                        Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
 
-        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
-                (car, ready) -> {
-                    if (!ready) {
-                        return;
-                    }
-                    mEnrollmentManager = (CarTrustAgentEnrollmentManager) car
-                            .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
-                });
-
-        mShortAnimDuration = container.getResources()
-                .getInteger(android.R.integer.config_shortAnimTime);
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
         if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
             // User0 is unlocked, switched to the initial user
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
index a27dd34..71847bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
@@ -18,33 +18,33 @@
 
 import android.annotation.NonNull;
 import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.content.Context;
 import android.util.Log;
 
+import com.android.systemui.car.CarServiceProvider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Helper class for connecting to the {@link CarPowerManager} and listening for power state changes.
  */
+@Singleton
 public class PowerManagerHelper {
     public static final String TAG = "PowerManagerHelper";
 
-    private final Context mContext;
-    private final CarPowerStateListener mCarPowerStateListener;
+    private final CarServiceProvider mCarServiceProvider;
 
-    private Car mCar;
     private CarPowerManager mCarPowerManager;
+    private CarPowerStateListener mCarPowerStateListener;
 
-    private final CarServiceLifecycleListener mCarServiceLifecycleListener;
+    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener;
 
-    PowerManagerHelper(Context context, @NonNull CarPowerStateListener listener) {
-        mContext = context;
-        mCarPowerStateListener = listener;
-        mCarServiceLifecycleListener = (car, ready) -> {
-            if (!ready) {
-                return;
-            }
+    @Inject
+    PowerManagerHelper(CarServiceProvider carServiceProvider) {
+        mCarServiceProvider = carServiceProvider;
+        mCarServiceLifecycleListener = car -> {
             Log.d(TAG, "Car Service connected");
             mCarPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE);
             if (mCarPowerManager != null) {
@@ -56,10 +56,16 @@
     }
 
     /**
+     * Sets a {@link CarPowerStateListener}. Should be set before {@link #connectToCarService()}.
+     */
+    void setCarPowerStateListener(@NonNull CarPowerStateListener listener) {
+        mCarPowerStateListener = listener;
+    }
+
+    /**
      * Connect to Car service.
      */
     void connectToCarService() {
-        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
-                mCarServiceLifecycleListener);
+        mCarServiceProvider.addListener(mCarServiceLifecycleListener);
     }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
index 76126fc..908aaad 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
@@ -35,7 +35,7 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
+import com.android.systemui.navigationbar.car.hvac.TemperatureView;
 
 /**
  * Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
index 9d39684..5a34436 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 
+import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.VolumeDialog;
 
@@ -30,13 +31,20 @@
 @Singleton
 public class CarVolumeDialogComponent extends VolumeDialogComponent {
 
+    private CarVolumeDialogImpl mCarVolumeDialog;
+
     @Inject
     public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
-            VolumeDialogControllerImpl volumeDialogController) {
+            VolumeDialogControllerImpl volumeDialogController,
+            CarServiceProvider carServiceProvider) {
         super(context, keyguardViewMediator, volumeDialogController);
+        mCarVolumeDialog.setCarServiceProvider(carServiceProvider);
     }
 
+    /** This method is called while calling the super constructor. */
+    @Override
     protected VolumeDialog createDefault() {
-        return new CarVolumeDialogImpl(mContext);
+        mCarVolumeDialog = new CarVolumeDialogImpl(mContext);
+        return mCarVolumeDialog;
     }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 09223e8..367959e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -24,7 +24,6 @@
 import android.app.Dialog;
 import android.app.KeyguardManager;
 import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
 import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -56,6 +55,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.plugins.VolumeDialog;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -95,7 +95,6 @@
     private CustomDialog mDialog;
     private RecyclerView mListView;
     private CarVolumeItemAdapter mVolumeItemsAdapter;
-    private Car mCar;
     private CarAudioManager mCarAudioManager;
     private boolean mHovering;
     private int mCurrentlyDisplayingGroupId;
@@ -147,30 +146,28 @@
                 }
             };
 
-    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
-        if (!ready) {
-            return;
-        }
-        mExpanded = false;
-        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
-        int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
-        // Populates volume slider items from volume groups to UI.
-        for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
-            VolumeItem volumeItem = getVolumeItemForUsages(
-                    mCarAudioManager.getUsagesForVolumeGroupId(groupId));
-            mAvailableVolumeItems.add(volumeItem);
-            // The first one is the default item.
-            if (groupId == 0) {
-                clearAllAndSetupDefaultCarVolumeLineItem(0);
-            }
-        }
+    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceOnConnectedListener =
+            car -> {
+                mExpanded = false;
+                mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+                int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
+                // Populates volume slider items from volume groups to UI.
+                for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
+                    VolumeItem volumeItem = getVolumeItemForUsages(
+                            mCarAudioManager.getUsagesForVolumeGroupId(groupId));
+                    mAvailableVolumeItems.add(volumeItem);
+                    // The first one is the default item.
+                    if (groupId == 0) {
+                        clearAllAndSetupDefaultCarVolumeLineItem(0);
+                    }
+                }
 
-        // If list is already initiated, update its content.
-        if (mVolumeItemsAdapter != null) {
-            mVolumeItemsAdapter.notifyDataSetChanged();
-        }
-        mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
-    };
+                // If list is already initiated, update its content.
+                if (mVolumeItemsAdapter != null) {
+                    mVolumeItemsAdapter.notifyDataSetChanged();
+                }
+                mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
+            };
 
     public CarVolumeDialogImpl(Context context) {
         mContext = context;
@@ -181,6 +178,11 @@
                 R.integer.car_volume_dialog_display_hovering_timeout);
     }
 
+    /** Sets a {@link CarServiceProvider} which connects to the audio service. */
+    public void setCarServiceProvider(CarServiceProvider carServiceProvider) {
+        carServiceProvider.addListener(mCarServiceOnConnectedListener);
+    }
+
     private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
         return carAudioManager.getGroupVolume(volumeGroupId);
     }
@@ -196,8 +198,6 @@
     @Override
     public void init(int windowType, Callback callback) {
         initDialog();
-        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
-                mCarServiceLifecycleListener);
     }
 
     @Override
@@ -205,12 +205,6 @@
         mHandler.removeCallbacksAndMessages(/* token= */ null);
 
         cleanupAudioManager();
-        // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup
-        // audio manager beforehand.
-        if (mCar != null) {
-            mCar.disconnect();
-            mCar = null;
-        }
     }
 
     private void initDialog() {
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
index 901d200..642b114 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
@@ -31,8 +31,8 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.car.hvac.HvacController;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.car.hvac.HvacController;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 
 import org.junit.Before;
@@ -41,8 +41,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import dagger.Lazy;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -50,17 +48,17 @@
 
     private CarNavigationBarController mCarNavigationBar;
     private NavigationBarViewFactory mNavigationBarViewFactory;
-    private Lazy<HvacController> mHvacControllerLazy;
     private TestableResources mTestableResources;
 
     @Mock
+    private CarFacetButtonController mCarFacetButtonController;
+    @Mock
     private HvacController mHvacController;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mNavigationBarViewFactory = new NavigationBarViewFactory(mContext);
-        mHvacControllerLazy = () -> mHvacController;
         mTestableResources = mContext.getOrCreateTestableResources();
 
         // Needed to inflate top navigation bar.
@@ -71,7 +69,7 @@
     @Test
     public void testConnectToHvac_callsConnect() {
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         mCarNavigationBar.connectToHvac();
 
@@ -81,7 +79,7 @@
     @Test
     public void testRemoveAllFromHvac_callsRemoveAll() {
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         mCarNavigationBar.removeAllFromHvac();
 
@@ -92,7 +90,7 @@
     public void testGetBottomWindow_bottomDisabled_returnsNull() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getBottomWindow();
 
@@ -103,7 +101,7 @@
     public void testGetBottomWindow_bottomEnabled_returnsWindow() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getBottomWindow();
 
@@ -114,7 +112,7 @@
     public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window1 = mCarNavigationBar.getBottomWindow();
         ViewGroup window2 = mCarNavigationBar.getBottomWindow();
@@ -126,7 +124,7 @@
     public void testGetLeftWindow_leftDisabled_returnsNull() {
         mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         ViewGroup window = mCarNavigationBar.getLeftWindow();
         assertThat(window).isNull();
     }
@@ -135,7 +133,7 @@
     public void testGetLeftWindow_leftEnabled_returnsWindow() {
         mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getLeftWindow();
 
@@ -146,7 +144,7 @@
     public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() {
         mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window1 = mCarNavigationBar.getLeftWindow();
         ViewGroup window2 = mCarNavigationBar.getLeftWindow();
@@ -158,7 +156,7 @@
     public void testGetRightWindow_rightDisabled_returnsNull() {
         mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getRightWindow();
 
@@ -169,7 +167,7 @@
     public void testGetRightWindow_rightEnabled_returnsWindow() {
         mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getRightWindow();
 
@@ -180,7 +178,7 @@
     public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() {
         mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window1 = mCarNavigationBar.getRightWindow();
         ViewGroup window2 = mCarNavigationBar.getRightWindow();
@@ -192,7 +190,7 @@
     public void testSetBottomWindowVisibility_setTrue_isVisible() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getBottomWindow();
         mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE);
@@ -204,7 +202,7 @@
     public void testSetBottomWindowVisibility_setFalse_isGone() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getBottomWindow();
         mCarNavigationBar.setBottomWindowVisibility(View.GONE);
@@ -216,7 +214,7 @@
     public void testSetLeftWindowVisibility_setTrue_isVisible() {
         mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getLeftWindow();
         mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE);
@@ -228,7 +226,7 @@
     public void testSetLeftWindowVisibility_setFalse_isGone() {
         mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getLeftWindow();
         mCarNavigationBar.setLeftWindowVisibility(View.GONE);
@@ -240,7 +238,7 @@
     public void testSetRightWindowVisibility_setTrue_isVisible() {
         mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getRightWindow();
         mCarNavigationBar.setRightWindowVisibility(View.VISIBLE);
@@ -252,7 +250,7 @@
     public void testSetRightWindowVisibility_setFalse_isGone() {
         mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         ViewGroup window = mCarNavigationBar.getRightWindow();
         mCarNavigationBar.setRightWindowVisibility(View.GONE);
@@ -264,7 +262,7 @@
     public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
@@ -279,7 +277,7 @@
     public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
@@ -292,7 +290,7 @@
     public void testRegisterNotificationController_createViewFirst_registrationSuccessful() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         CarNavigationBarController.NotificationsShadeController controller =
@@ -309,7 +307,7 @@
     public void testRegisterNotificationController_registerFirst_registrationSuccessful() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
 
         mCarNavigationBar.registerNotificationController(
                 mock(CarNavigationBarController.NotificationsShadeController.class));
@@ -324,7 +322,7 @@
     public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
 
@@ -337,7 +335,7 @@
     public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
 
@@ -350,7 +348,7 @@
     public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
 
@@ -365,7 +363,7 @@
     public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
 
@@ -380,7 +378,7 @@
     public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
 
@@ -395,7 +393,7 @@
     public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() {
         mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
         mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
-                mHvacControllerLazy);
+                () -> mCarFacetButtonController, () -> mHvacController);
         CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
         CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
 
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index af96982..4a50210 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -162,12 +162,12 @@
             final String title;
             final UUID storageUuid;
             if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
-                // We currently only support a single emulated volume mounted at
+                // We currently only support a single emulated volume per user mounted at
                 // a time, and it's always considered the primary
                 if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
                 rootId = ROOT_ID_PRIMARY_EMULATED;
 
-                if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
+                if (volume.isPrimaryEmulatedForUser(userId)) {
                     // This is basically the user's primary device storage.
                     // Use device name for the volume since this is likely same thing
                     // the user sees when they mount their phone on another device.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index df30c24..4b4861a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -212,15 +212,21 @@
     }
 
     private void dispatchAudioModeChanged() {
-        mDeviceManager.dispatchAudioModeChanged();
+        for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
+            cachedDevice.onAudioModeChanged();
+        }
         for (BluetoothCallback callback : mCallbacks) {
             callback.onAudioModeChanged();
         }
     }
 
-    private void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
+    @VisibleForTesting
+    void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
             int bluetoothProfile) {
-        mDeviceManager.onActiveDeviceChanged(activeDevice, bluetoothProfile);
+        for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
+            boolean isActive = Objects.equals(cachedDevice, activeDevice);
+            cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
+        }
         for (BluetoothCallback callback : mCallbacks) {
             callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index f243199..9f71033 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -26,7 +26,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -229,14 +228,6 @@
         }
     }
 
-    public synchronized void onActiveDeviceChanged(CachedBluetoothDevice activeDevice,
-            int bluetoothProfile) {
-        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
-            boolean isActive = Objects.equals(cachedDevice, activeDevice);
-            cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
-        }
-    }
-
     public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
             cachedDevice, int state) {
         return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
@@ -257,12 +248,6 @@
         }
     }
 
-    public synchronized void dispatchAudioModeChanged() {
-        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
-            cachedDevice.onAudioModeChanged();
-        }
-    }
-
     private void log(String msg) {
         if (DEBUG) {
             Log.d(TAG, msg);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 2c70cbb..ba1dc64 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.settingslib.bluetooth;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
@@ -41,6 +43,9 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothEventManagerTest {
 
@@ -54,10 +59,24 @@
     private CachedBluetoothDevice mCachedBluetoothDevice;
     @Mock
     private BluetoothDevice mBluetoothDevice;
+    @Mock
+    private HeadsetProfile mHfpProfile;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private HearingAidProfile mHearingAidProfile;
+    @Mock
+    private BluetoothDevice mDevice1;
+    @Mock
+    private BluetoothDevice mDevice2;
+    @Mock
+    private LocalBluetoothProfileManager mLocalProfileManager;
 
     private Context mContext;
     private Intent mIntent;
     private BluetoothEventManager mBluetoothEventManager;
+    private CachedBluetoothDevice mCachedDevice1;
+    private CachedBluetoothDevice mCachedDevice2;
 
     @Before
     public void setUp() {
@@ -67,6 +86,12 @@
         mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter,
                 mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+        when(mHfpProfile.isProfileReady()).thenReturn(true);
+        when(mA2dpProfile.isProfileReady()).thenReturn(true);
+        when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+
+        mCachedDevice1 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1);
+        mCachedDevice2 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2);
     }
 
     @Test
@@ -194,4 +219,129 @@
         verify(mBluetoothCallback, never()).onAclConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothAdapter.STATE_CONNECTED);
     }
+
+    /**
+     * Test to verify onActiveDeviceChanged().
+     */
+    @Test
+    public void dispatchActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
+        final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        cachedDevices.add(mCachedDevice1);
+        cachedDevices.add(mCachedDevice2);
+
+        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+
+        // Connect both devices for A2DP and HFP
+        mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+
+        // Verify that both devices are connected and none is Active
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+
+        // The first device is active for A2DP, the second device is active for HFP
+        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
+        mBluetoothEventManager
+                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+        // The first device is active for A2DP and HFP
+        mBluetoothEventManager
+                .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+
+        // The second device is active for A2DP and HFP
+        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.A2DP);
+        mBluetoothEventManager
+                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+        // No active device for A2DP
+        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+        // No active device for HFP
+        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+    }
+
+    /**
+     * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
+     */
+    @Test
+    public void dispatchActiveDeviceChanged_withA2dpAndHearingAid() {
+        final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        cachedDevices.add(mCachedDevice1);
+        cachedDevices.add(mCachedDevice2);
+
+        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+
+        // Connect device1 for A2DP and HFP and device2 for Hearing Aid
+        mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+        // Verify that both devices are connected and none is Active
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+
+        // The first device is active for A2DP and HFP
+        mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
+        mBluetoothEventManager
+                .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+
+        // The second device is active for Hearing Aid and the first device is not active
+        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
+        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
+        mBluetoothEventManager
+                .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEARING_AID);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();
+
+        // No active device for Hearing Aid
+        mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+        assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 806f22f..aef7fae 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -26,7 +26,6 @@
 
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 
 import org.junit.Before;
@@ -50,8 +49,6 @@
     private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
     private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
     private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
-    private final static String DEVICE_SUMMARY_1 = "summary 1";
-    private final static String DEVICE_SUMMARY_2 = "summary 2";
     private final static long HISYNCID1 = 10;
     private final static long HISYNCID2 = 11;
     private final BluetoothClass DEVICE_CLASS_1 =
@@ -401,124 +398,4 @@
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
         assertThat(mCachedDeviceManager.onDeviceDisappeared(cachedDevice1)).isTrue();
     }
-
-    /**
-     * Test to verify onActiveDeviceChanged().
-     */
-    @Test
-    public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
-        assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
-        assertThat(cachedDevice2).isNotNull();
-
-        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-
-        // Connect both devices for A2DP and HFP
-        cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        cachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        cachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-
-        // Verify that both devices are connected and none is Active
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-
-        // The first device is active for A2DP, the second device is active for HFP
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
-        // The first device is active for A2DP and HFP
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-
-        // The second device is active for A2DP and HFP
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.A2DP);
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
-        // No active device for A2DP
-        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
-        // No active device for HFP
-        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-    }
-
-    /**
-     * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
-     */
-    @Test
-    public void onActiveDeviceChanged_withA2dpAndHearingAid() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
-        assertThat(cachedDevice1).isNotNull();
-        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
-        assertThat(cachedDevice2).isNotNull();
-
-        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-
-        // Connect device1 for A2DP and HFP and device2 for Hearing Aid
-        cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
-        cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-        cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
-
-        // Verify that both devices are connected and none is Active
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-
-        // The first device is active for A2DP and HFP
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-
-        // The second device is active for Hearing Aid and the first device is not active
-        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
-        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEARING_AID);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();
-
-        // No active device for Hearing Aid
-        mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-        assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-    }
 }
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml
new file mode 100644
index 0000000..1947f58
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="M12,3c-4.97,0 -9,4.03 -9,9c0,1.39 0.32,2.69 0.88,3.86l1.53,-1.53C5.15,13.6 5,12.82 5,12c0,-3.86 3.14,-7 7,-7s7,3.14 7,7s-3.14,7 -7,7c-0.83,0 -1.62,-0.15 -2.35,-0.42l-1.53,1.53C9.3,20.67 10.61,21 12,21c4.97,0 9,-4.03 9,-9C21,7.03 16.97,3 12,3z"
+        android:fillColor="#000000"/>
+    <path
+        android:pathData="M12.99,15.99l2,0l0,-7l-7,0l0,2l3.59,0l-8.79,8.8l1.41,1.41l8.79,-8.79z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 87de9d4..964a591 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -220,6 +220,58 @@
             android:orientation="vertical">
 
             <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+                android:id="@+id/bubble"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="@dimen/notification_importance_button_padding"
+                android:layout_marginBottom="@dimen/notification_importance_button_separation"
+                android:clickable="true"
+                android:focusable="true"
+                android:background="@drawable/notification_guts_priority_button_bg"
+                android:orientation="vertical">
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:gravity="center"
+                >
+                    <ImageView
+                        android:id="@+id/bubble_icon"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:src="@drawable/ic_create_bubble"
+                        android:background="@android:color/transparent"
+                        android:tint="@color/notification_guts_priority_contents"
+                        android:clickable="false"
+                        android:focusable="false"/>
+                    <TextView
+                        android:id="@+id/bubble_label"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+                        android:layout_weight="1"
+                        android:ellipsize="end"
+                        android:maxLines="1"
+                        android:clickable="false"
+                        android:focusable="false"
+                        android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+                        android:text="@string/notification_bubble_title"/>
+                </LinearLayout>
+                <TextView
+                    android:id="@+id/bubble_summary"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+                    android:visibility="gone"
+                    android:text="@string/notification_channel_summary_bubble"
+                    android:clickable="false"
+                    android:focusable="false"
+                    android:ellipsize="end"
+                    android:maxLines="2"
+                    android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+            </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+            <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
                 android:id="@+id/alert"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0082949..19daa90 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1717,12 +1717,18 @@
     <!-- [CHAR LIMIT=100] Notification Importance title -->
     <string name="notification_alert_title">Alerting</string>
 
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_bubble_title">Bubble</string>
+
     <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
     <string name="notification_channel_summary_low">Helps you focus without sound or vibration.</string>
 
     <!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary -->
     <string name="notification_channel_summary_default">Gets your attention with sound or vibration.</string>
 
+    <!-- [CHAR LIMIT=150] Notification Importance title: bubble level summary -->
+    <string name="notification_channel_summary_bubble">Keeps your attention with a floating shortcut to this content.</string>
+
     <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
     <string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 91ee1b9..dca5c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -125,6 +125,7 @@
 import com.android.systemui.util.leak.LeakDetector;
 import com.android.systemui.util.leak.LeakReporter;
 import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -332,6 +333,7 @@
     @Inject Lazy<CommandQueue> mCommandQueue;
     @Inject Lazy<Recents> mRecents;
     @Inject Lazy<StatusBar> mStatusBar;
+    @Inject Lazy<DisplayWindowController> mDisplayWindowController;
 
     @Inject
     public Dependency() {
@@ -523,6 +525,7 @@
         mProviders.put(CommandQueue.class, mCommandQueue::get);
         mProviders.put(Recents.class, mRecents::get);
         mProviders.put(StatusBar.class, mStatusBar::get);
+        mProviders.put(DisplayWindowController.class, mDisplayWindowController::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/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 6949640..1a4c327 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -47,7 +47,9 @@
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 
+import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.widget.AdaptiveIcon;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
@@ -61,10 +63,13 @@
 
     private Context mContext;
     private LinearLayout mMediaNotifView;
+    private View mSeamless;
     private MediaSession.Token mToken;
     private MediaController mController;
     private int mWidth;
     private int mHeight;
+    private int mForegroundColor;
+    private int mBackgroundColor;
 
     /**
      *
@@ -93,15 +98,17 @@
      * @param iconColor foreground color (for text, icons)
      * @param bgColor background color
      * @param actionsContainer a LinearLayout containing the media action buttons
-     * @param notif
+     * @param notif reference to original notification
+     * @param device current playback device
      */
     public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
-            View actionsContainer, Notification notif) {
+            View actionsContainer, Notification notif, MediaDevice device) {
         Log.d(TAG, "got media session: " + token);
         mToken = token;
+        mForegroundColor = iconColor;
+        mBackgroundColor = bgColor;
         mController = new MediaController(mContext, token);
         MediaMetadata mMediaMetadata = mController.getMetadata();
-
         if (mMediaMetadata == null) {
             Log.e(TAG, "Media metadata was null");
             return;
@@ -123,9 +130,6 @@
         headerView.removeAllViews();
         headerView.addView(result);
 
-        View seamless = headerView.findViewById(com.android.internal.R.id.media_seamless);
-        seamless.setVisibility(View.VISIBLE);
-
         // App icon
         ImageView appIcon = headerView.findViewById(com.android.internal.R.id.icon);
         Drawable iconDrawable = icon.loadDrawable(mContext);
@@ -168,23 +172,11 @@
         }
 
         // Transfer chip
-        View transferBackgroundView = headerView.findViewById(
-                com.android.internal.R.id.media_seamless);
-        LinearLayout viewLayout = (LinearLayout) transferBackgroundView;
-        RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
-        GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
-        rect.setStroke(2, iconColor);
-        rect.setColor(bgColor);
-        ImageView transferIcon = headerView.findViewById(
-                com.android.internal.R.id.media_seamless_image);
-        transferIcon.setBackgroundColor(bgColor);
-        transferIcon.setImageTintList(ColorStateList.valueOf(iconColor));
-        TextView transferText = headerView.findViewById(
-                com.android.internal.R.id.media_seamless_text);
-        transferText.setTextColor(iconColor);
-
+        mSeamless = headerView.findViewById(com.android.internal.R.id.media_seamless);
+        mSeamless.setVisibility(View.VISIBLE);
+        updateChip(device);
         ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
-        transferBackgroundView.setOnClickListener(v -> {
+        mSeamless.setOnClickListener(v -> {
             final Intent intent = new Intent()
                     .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
             mActivityStarter.startActivity(intent, false, true /* dismissShade */,
@@ -219,10 +211,13 @@
                 com.android.internal.R.id.action3,
                 com.android.internal.R.id.action4
         };
-        for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
+
+        int i = 0;
+        for (; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
             ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
             ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
-            if (thatBtn == null || thatBtn.getDrawable() == null) {
+            if (thatBtn == null || thatBtn.getDrawable() == null
+                    || thatBtn.getVisibility() != View.VISIBLE) {
                 thisBtn.setVisibility(View.GONE);
                 continue;
             }
@@ -235,6 +230,13 @@
                 thatBtn.performClick();
             });
         }
+
+        // Hide any unused buttons
+        for (; i < actionIds.length; i++) {
+            ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+            thisBtn.setVisibility(View.GONE);
+            Log.d(TAG, "hid a button");
+        }
     }
 
     public MediaSession.Token getMediaSessionToken() {
@@ -284,6 +286,7 @@
             mMediaNotifView.setBackground(roundedDrawable);
         } else {
             Log.e(TAG, "No album art available");
+            mMediaNotifView.setBackground(null);
         }
     }
 
@@ -303,4 +306,41 @@
 
         return cropped;
     }
+
+    protected void updateChip(MediaDevice device) {
+        if (mSeamless == null) {
+            return;
+        }
+        ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
+
+        // Update the outline color
+        LinearLayout viewLayout = (LinearLayout) mSeamless;
+        RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
+        GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
+        rect.setStroke(2, mForegroundColor);
+        rect.setColor(mBackgroundColor);
+
+        ImageView iconView = mSeamless.findViewById(com.android.internal.R.id.media_seamless_image);
+        TextView deviceName = mSeamless.findViewById(com.android.internal.R.id.media_seamless_text);
+        deviceName.setTextColor(fgTintList);
+
+        if (device != null) {
+            Drawable icon = device.getIcon();
+            iconView.setVisibility(View.VISIBLE);
+            iconView.setImageTintList(fgTintList);
+
+            if (icon instanceof AdaptiveIcon) {
+                AdaptiveIcon aIcon = (AdaptiveIcon) icon;
+                aIcon.setBackgroundColor(mBackgroundColor);
+                iconView.setImageDrawable(aIcon);
+            } else {
+                iconView.setImageDrawable(icon);
+            }
+            deviceName.setText(device.getName());
+        } else {
+            // Reset to default
+            iconView.setVisibility(View.GONE);
+            deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index cac9025..5e98f93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -46,6 +46,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.Dependency;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
@@ -70,6 +72,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -92,6 +95,8 @@
 
     private final LinearLayout mMediaCarousel;
     private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
+    private LocalMediaManager mLocalMediaManager;
+    private MediaDevice mDevice;
 
     protected boolean mExpanded;
     protected boolean mListening;
@@ -117,6 +122,31 @@
     private final PluginManager mPluginManager;
     private NPVPluginManager mNPVPluginManager;
 
+    private final LocalMediaManager.DeviceCallback mDeviceCallback =
+            new LocalMediaManager.DeviceCallback() {
+        @Override
+        public void onDeviceListUpdate(List<MediaDevice> devices) {
+            MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
+            // Check because this can be called several times while changing devices
+            if (mDevice == null || !mDevice.equals(currentDevice)) {
+                mDevice = currentDevice;
+                for (QSMediaPlayer p : mMediaPlayers) {
+                    p.updateChip(mDevice);
+                }
+            }
+        }
+
+        @Override
+        public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
+            if (mDevice == null || !mDevice.equals(device)) {
+                mDevice = device;
+                for (QSMediaPlayer p : mMediaPlayers) {
+                    p.updateChip(mDevice);
+                }
+            }
+        }
+    };
+
     public QSPanel(Context context) {
         this(context, null);
     }
@@ -208,6 +238,11 @@
             Log.e(TAG, "Tried to add media session without player!");
             return;
         }
+        if (token == null) {
+            Log.e(TAG, "Media session token was null!");
+            return;
+        }
+
         QSMediaPlayer player = null;
         String packageName = notif.getPackageName();
         for (QSMediaPlayer p : mMediaPlayers) {
@@ -250,10 +285,17 @@
 
         Log.d(TAG, "setting player session");
         player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
-                notif.getNotification());
+                notif.getNotification(), mDevice);
 
         if (mMediaPlayers.size() > 0) {
             ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
+
+            // Set up listener for device changes
+            // TODO: integrate with MediaTransferManager?
+            mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+            mLocalMediaManager.startScan();
+            mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+            mLocalMediaManager.registerCallback(mDeviceCallback);
         }
     }
 
@@ -326,6 +368,10 @@
             mBrightnessMirrorController.removeCallback(this);
         }
         if (mDumpController != null) mDumpController.unregisterDumpable(this);
+        if (mLocalMediaManager != null) {
+            mLocalMediaManager.stopScan();
+            mLocalMediaManager.unregisterCallback(mDeviceCallback);
+        }
         super.onDetachedFromWindow();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index 3ec71ac..d7b8b83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -76,9 +76,11 @@
      * @param iconColor foreground color (for text, icons)
      * @param bgColor background color
      * @param actionsContainer a LinearLayout containing the media action buttons
+     * @param actionsToShow indices of which actions to display in the mini player
+     *                      (max 3: Notification.MediaStyle.MAX_MEDIA_BUTTONS_IN_COMPACT)
      */
     public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
-            View actionsContainer) {
+            View actionsContainer, int[] actionsToShow) {
         Log.d(TAG, "Setting media session: " + token);
         mToken = token;
         mController = new MediaController(mContext, token);
@@ -110,32 +112,46 @@
         titleText.setText(songName);
         titleText.setTextColor(iconColor);
 
-        // Action buttons
-        LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
+        // Buttons we can display
         final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
 
-        // TODO some apps choose different buttons to show in compact mode
+        // Existing buttons in the notification
+        LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
         final int[] notifActionIds = {
+                com.android.internal.R.id.action0,
                 com.android.internal.R.id.action1,
                 com.android.internal.R.id.action2,
-                com.android.internal.R.id.action3
+                com.android.internal.R.id.action3,
+                com.android.internal.R.id.action4
         };
-        for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
-            ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
-            ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
-            if (thatBtn == null || thatBtn.getDrawable() == null) {
-                thisBtn.setVisibility(View.GONE);
-                continue;
+
+        int i = 0;
+        if (actionsToShow != null) {
+            int maxButtons = Math.min(actionsToShow.length, parentActionsLayout.getChildCount());
+            maxButtons = Math.min(maxButtons, actionIds.length);
+            for (; i < maxButtons; i++) {
+                ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+                int thatId = notifActionIds[actionsToShow[i]];
+                ImageButton thatBtn = parentActionsLayout.findViewById(thatId);
+                if (thatBtn == null || thatBtn.getDrawable() == null
+                        || thatBtn.getVisibility() != View.VISIBLE) {
+                    thisBtn.setVisibility(View.GONE);
+                    continue;
+                }
+
+                Drawable thatIcon = thatBtn.getDrawable();
+                thisBtn.setImageDrawable(thatIcon.mutate());
+                thisBtn.setVisibility(View.VISIBLE);
+                thisBtn.setOnClickListener(v -> {
+                    thatBtn.performClick();
+                });
             }
+        }
 
-            Drawable thatIcon = thatBtn.getDrawable();
-            thisBtn.setImageDrawable(thatIcon.mutate());
-            thisBtn.setVisibility(View.VISIBLE);
-
-            thisBtn.setOnClickListener(v -> {
-                Log.d(TAG, "clicking on other button");
-                thatBtn.performClick();
-            });
+        // Hide any unused buttons
+        for (; i < actionIds.length; i++) {
+            ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+            thisBtn.setVisibility(View.GONE);
         }
     }
 
@@ -186,6 +202,7 @@
             mMediaNotifView.setBackground(roundedDrawable);
         } else {
             Log.e(TAG, "No album art available");
+            mMediaNotifView.setBackground(null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
index 926ae71..b21c65e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
@@ -19,10 +19,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.service.notification.StatusBarNotification;
 import android.util.FeatureFlagUtils;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -30,19 +32,29 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.internal.R;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.widget.AdaptiveIcon;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Class for handling MediaTransfer state over a set of notifications.
  */
 public class MediaTransferManager {
     private final Context mContext;
     private final ActivityStarter mActivityStarter;
+    private MediaDevice mDevice;
+    private List<View> mViews = new ArrayList<>();
+    private LocalMediaManager mLocalMediaManager;
+
+    private static final String TAG = "MediaTransferManager";
 
     private final View.OnClickListener mOnClickHandler = new View.OnClickListener() {
         @Override
@@ -70,9 +82,50 @@
         }
     };
 
+    private final LocalMediaManager.DeviceCallback mMediaDeviceCallback =
+            new LocalMediaManager.DeviceCallback() {
+        @Override
+        public void onDeviceListUpdate(List<MediaDevice> devices) {
+            MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
+            // Check because this can be called several times while changing devices
+            if (mDevice == null || !mDevice.equals(currentDevice)) {
+                mDevice = currentDevice;
+                updateAllChips();
+            }
+        }
+
+        @Override
+        public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
+            if (mDevice == null || !mDevice.equals(device)) {
+                mDevice = device;
+                updateAllChips();
+            }
+        }
+    };
+
     public MediaTransferManager(Context context) {
         mContext = context;
         mActivityStarter = Dependency.get(ActivityStarter.class);
+        mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+    }
+
+    /**
+     * Mark a view as removed. If no views remain the media device listener will be unregistered.
+     * @param root
+     */
+    public void setRemoved(View root) {
+        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
+                || mLocalMediaManager == null || root == null) {
+            return;
+        }
+        View view = root.findViewById(com.android.internal.R.id.media_seamless);
+        if (mViews.remove(view)) {
+            if (mViews.size() == 0) {
+                mLocalMediaManager.unregisterCallback(mMediaDeviceCallback);
+            }
+        } else {
+            Log.e(TAG, "Tried to remove unknown view " + view);
+        }
     }
 
     private ExpandableNotificationRow getRowForParent(ViewParent parent) {
@@ -92,7 +145,8 @@
      * @param entry The entry of MediaTransfer action button.
      */
     public void applyMediaTransferView(ViewGroup root, NotificationEntry entry) {
-        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)) {
+        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
+                || mLocalMediaManager == null || root == null) {
             return;
         }
 
@@ -103,23 +157,59 @@
 
         view.setVisibility(View.VISIBLE);
         view.setOnClickListener(mOnClickHandler);
+        if (!mViews.contains(view)) {
+            mViews.add(view);
+            if (mViews.size() == 1) {
+                mLocalMediaManager.registerCallback(mMediaDeviceCallback);
+            }
+        }
 
+        // Initial update
+        mLocalMediaManager.startScan();
+        mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+        updateChip(view);
+    }
+
+    private void updateAllChips() {
+        for (View view : mViews) {
+            updateChip(view);
+        }
+    }
+
+    private void updateChip(View view) {
         ExpandableNotificationRow enr = getRowForParent(view.getParent());
-        int color = enr.getNotificationHeader().getOriginalIconColor();
-        ColorStateList tintList = ColorStateList.valueOf(color);
+        int fgColor = enr.getNotificationHeader().getOriginalIconColor();
+        ColorStateList fgTintList = ColorStateList.valueOf(fgColor);
+        int bgColor = enr.getCurrentBackgroundTint();
 
-        // Update the outline color
+        // Update outline color
         LinearLayout viewLayout = (LinearLayout) view;
         RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
         GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
-        rect.setStroke(2, color);
+        rect.setStroke(2, fgColor);
+        rect.setColor(bgColor);
 
-        // Update the image color
-        ImageView image = view.findViewById(R.id.media_seamless_image);
-        image.setImageTintList(tintList);
+        ImageView iconView = view.findViewById(com.android.internal.R.id.media_seamless_image);
+        TextView deviceName = view.findViewById(com.android.internal.R.id.media_seamless_text);
+        deviceName.setTextColor(fgTintList);
 
-        // Update the text color
-        TextView text = view.findViewById(R.id.media_seamless_text);
-        text.setTextColor(tintList);
+        if (mDevice != null) {
+            Drawable icon = mDevice.getIcon();
+            iconView.setVisibility(View.VISIBLE);
+            iconView.setImageTintList(fgTintList);
+
+            if (icon instanceof AdaptiveIcon) {
+                AdaptiveIcon aIcon = (AdaptiveIcon) icon;
+                aIcon.setBackgroundColor(bgColor);
+                iconView.setImageDrawable(aIcon);
+            } else {
+                iconView.setImageDrawable(icon);
+            }
+            deviceName.setText(mDevice.getName());
+        } else {
+            // Reset to default
+            iconView.setVisibility(View.GONE);
+            deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 9b31234..e48e819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -125,22 +125,21 @@
         return mAnimationRunning;
     }
 
-    class AnimationRunner extends IRemoteAnimationRunner.Stub {
+    private class AnimationRunner extends IRemoteAnimationRunner.Stub {
 
-        private final ExpandableNotificationRow mSourceNotification;
-        private final ExpandAnimationParameters mParams;
+        private ExpandableNotificationRow mSourceNotification;
+        private final ExpandAnimationParameters mParams = new ExpandAnimationParameters();
         private final Rect mWindowCrop = new Rect();
         private final float mNotificationCornerRadius;
         private float mCornerRadius;
         private boolean mIsFullScreenLaunch = true;
         private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
 
-        public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
-            mSourceNotification = sourceNofitication;
-            mParams = new ExpandAnimationParameters();
-            mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification);
-            mNotificationCornerRadius = Math.max(mSourceNotification.getCurrentTopRoundness(),
-                    mSourceNotification.getCurrentBottomRoundness());
+        AnimationRunner(ExpandableNotificationRow sourceNotification) {
+            mSourceNotification = sourceNotification;
+            mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(sourceNotification);
+            mNotificationCornerRadius = Math.max(sourceNotification.getCurrentTopRoundness(),
+                    sourceNotification.getCurrentBottomRoundness());
         }
 
         @Override
@@ -155,6 +154,7 @@
                     setAnimationPending(false);
                     invokeCallback(iRemoteAnimationFinishedCallback);
                     mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+                    mSourceNotification = null;
                     return;
                 }
 
@@ -254,6 +254,7 @@
                 mCallback.onExpandAnimationFinished(mIsFullScreenLaunch);
                 applyParamsToNotification(null);
                 applyParamsToNotificationList(null);
+                mSourceNotification = null;
             }
 
         }
@@ -281,6 +282,7 @@
             mSourceNotification.post(() -> {
                 setAnimationPending(false);
                 mCallback.onLaunchAnimationCancelled();
+                mSourceNotification = null;
             });
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index b12c76c..d1b9a87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1546,9 +1546,11 @@
         }
         if (mExpandedWrapper != null) {
             mExpandedWrapper.setRemoved();
+            mMediaTransferManager.setRemoved(mExpandedChild);
         }
         if (mContractedWrapper != null) {
             mContractedWrapper.setRemoved();
+            mMediaTransferManager.setRemoved(mContractedChild);
         }
         if (mHeadsUpWrapper != null) {
             mHeadsUpWrapper.setRemoved();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f90e561..f67cd1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -319,7 +319,7 @@
                 packageName,
                 row.getEntry().getChannel(),
                 row.getUniqueChannels(),
-                sbn,
+                row.getEntry(),
                 mCheckSaveListener,
                 onSettingsClick,
                 onAppSettingsClick,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 148d83b..a9a4804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -65,7 +65,10 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.bubbles.BubbleExperimentConfig;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 
 import java.lang.annotation.Retention;
@@ -99,6 +102,7 @@
     // standard controls
     private static final int ACTION_ALERT = 5;
 
+    private TextView mBubbleDescriptionView;
     private TextView mPriorityDescriptionView;
     private TextView mSilentDescriptionView;
 
@@ -116,6 +120,7 @@
     private Set<NotificationChannel> mUniqueChannelsInRow;
     private NotificationChannel mSingleNotificationChannel;
     private int mStartingChannelImportance;
+    private boolean mStartedAsBubble;
     private boolean mWasShownHighPriority;
     private boolean mPressedApply;
     private boolean mPresentingChannelEditorDialog = false;
@@ -125,8 +130,15 @@
      * level; non-null once the user takes an action which indicates an explicit preference.
      */
     @Nullable private Integer mChosenImportance;
+    /**
+     * The last bubble setting chosen by the user. Null if the user has not chosen a bubble level;
+     * non-null once the user takes an action which indicates an explicit preference.
+     */
+    @Nullable private Boolean mChosenBubbleEnabled;
     private boolean mIsSingleDefaultChannel;
     private boolean mIsNonblockable;
+    private boolean mIsBubbleable;
+    private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
     private AnimatorSet mExpandAnimation;
     private boolean mIsDeviceProvisioned;
@@ -137,18 +149,27 @@
     private NotificationGuts mGutsContainer;
     private Drawable mPkgIcon;
 
+    private BubbleController mBubbleController;
+
     /** Whether this view is being shown as part of the blocking helper. */
     private boolean mIsForBlockingHelper;
 
+    @VisibleForTesting
+    boolean mSkipPost = false;
+
     /**
      * String that describes how the user exit or quit out of this view, also used as a counter tag.
      */
     private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
+
     // used by standard ui
     private OnClickListener mOnAlert = v -> {
         mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         mChosenImportance = IMPORTANCE_DEFAULT;
+        if (mStartedAsBubble) {
+            mChosenBubbleEnabled = false;
+        }
         applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */);
     };
 
@@ -156,9 +177,19 @@
     private OnClickListener mOnSilent = v -> {
         mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
         mChosenImportance = IMPORTANCE_LOW;
+        if (mStartedAsBubble) {
+            mChosenBubbleEnabled = false;
+        }
         applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */);
     };
 
+    /** Used by standard ui (in an experiment) {@see BubbleExperimentConfig#allowNotifBubbleMenu} */
+    private OnClickListener mOnBubble = v -> {
+        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+        mChosenBubbleEnabled = true;
+        applyAlertingBehavior(BEHAVIOR_BUBBLE, true /* userTriggered */);
+    };
+
     // used by standard ui
     private OnClickListener mOnDismissSettings = v -> {
         mPressedApply = true;
@@ -224,6 +255,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        mBubbleDescriptionView = findViewById(R.id.bubble_summary);
         mPriorityDescriptionView = findViewById(R.id.alert_summary);
         mSilentDescriptionView = findViewById(R.id.silence_summary);
     }
@@ -251,7 +283,7 @@
             final String pkg,
             final NotificationChannel notificationChannel,
             final Set<NotificationChannel> uniqueChannelsInRow,
-            final StatusBarNotification sbn,
+            final NotificationEntry entry,
             final CheckSaveListener checkSaveListener,
             final OnSettingsClickListener onSettingsClick,
             final OnAppSettingsClickListener onAppSettingsClick,
@@ -261,7 +293,7 @@
             boolean wasShownHighPriority)
             throws RemoteException {
         bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel,
-                uniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
+                uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick,
                 onAppSettingsClick, isDeviceProvisioned, isNonblockable,
                 false /* isBlockingHelper */,
                 importance, wasShownHighPriority);
@@ -274,7 +306,7 @@
             String pkg,
             NotificationChannel notificationChannel,
             Set<NotificationChannel> uniqueChannelsInRow,
-            StatusBarNotification sbn,
+            NotificationEntry entry,
             CheckSaveListener checkSaveListener,
             OnSettingsClickListener onSettingsClick,
             OnAppSettingsClickListener onAppSettingsClick,
@@ -288,10 +320,12 @@
         mMetricsLogger = Dependency.get(MetricsLogger.class);
         mVisualStabilityManager = visualStabilityManager;
         mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
+        mBubbleController = Dependency.get(BubbleController.class);
         mPackageName = pkg;
         mUniqueChannelsInRow = uniqueChannelsInRow;
         mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
-        mSbn = sbn;
+        mEntry = entry;
+        mSbn = entry.getSbn();
         mPm = pm;
         mAppSettingsClickListener = onAppSettingsClick;
         mAppName = mPackageName;
@@ -318,6 +352,9 @@
                     && numTotalChannels == 1;
         }
 
+        mIsBubbleable = mEntry.getBubbleMetadata() != null;
+        mStartedAsBubble = mEntry.isBubble();
+
         bindHeader();
         bindChannelDetails();
 
@@ -365,6 +402,7 @@
             findViewById(R.id.non_configurable_text).setVisibility(GONE);
             findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
             findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
+            findViewById(R.id.bubble).setVisibility(mIsBubbleable ? VISIBLE : GONE);
         }
 
         View turnOffButton = findViewById(R.id.turn_off_notifications);
@@ -378,12 +416,17 @@
 
         View silent = findViewById(R.id.silence);
         View alert = findViewById(R.id.alert);
+        View bubble = findViewById(R.id.bubble);
         silent.setOnClickListener(mOnSilent);
         alert.setOnClickListener(mOnAlert);
+        bubble.setOnClickListener(mOnBubble);
 
-        applyAlertingBehavior(
-                mWasShownHighPriority ? BEHAVIOR_ALERTING : BEHAVIOR_SILENT,
-                false /* userTriggered */);
+        int behavior = mStartedAsBubble
+                ? BEHAVIOR_BUBBLE
+                : mWasShownHighPriority
+                        ? BEHAVIOR_ALERTING
+                        : BEHAVIOR_SILENT;
+        applyAlertingBehavior(behavior, false /* userTriggered */);
     }
 
     private void bindHeader() {
@@ -544,6 +587,14 @@
                 }
             }
 
+            if (mChosenBubbleEnabled != null && mStartedAsBubble != mChosenBubbleEnabled) {
+                if (mChosenBubbleEnabled) {
+                    mBubbleController.onUserCreatedBubbleFromNotification(mEntry);
+                } else {
+                    mBubbleController.onUserDemotedBubbleFromNotification(mEntry);
+                }
+            }
+
             Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
             bgHandler.post(
                     new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
@@ -553,6 +604,16 @@
         }
     }
 
+    @Override
+    public boolean post(Runnable action) {
+        if (mSkipPost) {
+            action.run();
+            return true;
+        } else {
+            return super.post(action);
+        }
+    }
+
     private void applyAlertingBehavior(@AlertingBehavior int behavior, boolean userTriggered) {
         if (userTriggered) {
             TransitionSet transition = new TransitionSet();
@@ -569,6 +630,7 @@
             TransitionManager.beginDelayedTransition(this, transition);
         }
 
+        View bubble = findViewById(R.id.bubble);
         View alert = findViewById(R.id.alert);
         View silence = findViewById(R.id.silence);
 
@@ -576,33 +638,53 @@
             case BEHAVIOR_ALERTING:
                 mPriorityDescriptionView.setVisibility(VISIBLE);
                 mSilentDescriptionView.setVisibility(GONE);
+                mBubbleDescriptionView.setVisibility(GONE);
                 post(() -> {
                     alert.setSelected(true);
                     silence.setSelected(false);
+                    bubble.setSelected(false);
                 });
                 break;
-            case BEHAVIOR_SILENT:
 
+            case BEHAVIOR_SILENT:
                 mSilentDescriptionView.setVisibility(VISIBLE);
                 mPriorityDescriptionView.setVisibility(GONE);
+                mBubbleDescriptionView.setVisibility(GONE);
                 post(() -> {
                     alert.setSelected(false);
                     silence.setSelected(true);
+                    bubble.setSelected(false);
                 });
                 break;
+
+            case BEHAVIOR_BUBBLE:
+                mBubbleDescriptionView.setVisibility(VISIBLE);
+                mSilentDescriptionView.setVisibility(GONE);
+                mPriorityDescriptionView.setVisibility(GONE);
+                post(() -> {
+                    alert.setSelected(false);
+                    silence.setSelected(false);
+                    bubble.setSelected(true);
+                });
+                break;
+
             default:
                 throw new IllegalArgumentException("Unrecognized alerting behavior: " + behavior);
         }
 
         boolean isAChange = mWasShownHighPriority != (behavior == BEHAVIOR_ALERTING);
+        boolean isABubbleChange = mStartedAsBubble != (behavior == BEHAVIOR_BUBBLE);
         TextView done = findViewById(R.id.done);
-        done.setText(isAChange ? R.string.inline_ok_button : R.string.inline_done_button);
+        done.setText((isAChange || isABubbleChange)
+                ? R.string.inline_ok_button
+                : R.string.inline_done_button);
     }
 
     private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
         switch (action) {
             case ACTION_UNDO:
                 mChosenImportance = mStartingChannelImportance;
+                mChosenBubbleEnabled = mStartedAsBubble;
                 break;
             case ACTION_DELIVER_SILENTLY:
                 mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
@@ -685,6 +767,9 @@
         if (mChosenImportance != null) {
             mStartingChannelImportance = mChosenImportance;
         }
+        if (mChosenBubbleEnabled != null) {
+            mStartedAsBubble = mChosenBubbleEnabled;
+        }
         mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
         if (mIsForBlockingHelper) {
@@ -884,8 +969,9 @@
     }
 
     @Retention(SOURCE)
-    @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT})
+    @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT, BEHAVIOR_BUBBLE})
     private @interface AlertingBehavior {}
     private static final int BEHAVIOR_ALERTING = 0;
     private static final int BEHAVIOR_SILENT = 1;
+    private static final int BEHAVIOR_BUBBLE = 2;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index d0122c2..54c7141 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -183,6 +183,8 @@
                 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
 
         if (Utils.useQsMediaPlayer(mContext)) {
+            final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
+                    .getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
             StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
             QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
                     com.android.systemui.R.id.quick_qs_panel);
@@ -190,7 +192,8 @@
                     mRow.getStatusBarNotification().getNotification().getSmallIcon(),
                     getNotificationHeader().getOriginalIconColor(),
                     mRow.getCurrentBackgroundTint(),
-                    mActions);
+                    mActions,
+                    compactActions);
             QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
                     com.android.systemui.R.id.quick_settings_panel);
             bigPanel.addMediaSession(token,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 1ecc489..afaa593 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -90,14 +90,6 @@
         public void onCancelled() {
             pulseFinished();
         }
-
-        /**
-         * Whether to timeout wallpaper or not.
-         */
-        @Override
-        public boolean shouldTimeoutWallpaper() {
-            return mPulseReason == DozeEvent.PULSE_REASON_DOCKING;
-        }
     };
 
     @Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index a1af5e8..6aee194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -233,10 +233,6 @@
             mScrimController.setWakeLockScreenSensorActive(true);
         }
 
-        if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
-            mStatusBarWindowViewController.suppressWakeUpGesture(true);
-        }
-
         boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
                         && mWakeLockScreenPerformsAuth;
         // Set the state to pulsing, so ScrimController will know what to do once we ask it to
@@ -257,9 +253,6 @@
                 callback.onPulseFinished();
                 mStatusBar.updateNotificationPanelTouchState();
                 mScrimController.setWakeLockScreenSensorActive(false);
-                if (mStatusBarWindow != null) {
-                    mStatusBarWindowViewController.suppressWakeUpGesture(false);
-                }
                 setPulsing(false);
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f21a9a2..1454e25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -46,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -136,6 +137,7 @@
     private final KeyguardStateController mKeyguardStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final DozeParameters mDozeParameters;
+    private final DockManager mDockManager;
     private final AlarmTimeout mTimeTicker;
     private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
     private final Handler mHandler;
@@ -192,7 +194,8 @@
             AlarmManager alarmManager, KeyguardStateController keyguardStateController,
             @MainResources Resources resources,
             DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
+            DockManager dockManager) {
 
         mScrimStateListener = lightBarController::setScrimState;
 
@@ -209,6 +212,7 @@
         // to make sure that text on top of it is legible.
         mScrimBehindAlpha = mScrimBehindAlphaResValue;
         mDozeParameters = dozeParameters;
+        mDockManager = dockManager;
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onKeyguardFadingAwayChanged() {
@@ -234,7 +238,8 @@
 
         final ScrimState[] states = ScrimState.values();
         for (int i = 0; i < states.length; i++) {
-            states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters);
+            states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
+                    mDockManager);
             states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
         }
 
@@ -359,11 +364,6 @@
             return true;
         }
 
-        if (mState == ScrimState.PULSING
-                && mCallback != null && mCallback.shouldTimeoutWallpaper()) {
-            return true;
-        }
-
         return false;
     }
 
@@ -520,8 +520,7 @@
      * device is dozing when the light sensor is on.
      */
     public void setAodFrontScrimAlpha(float alpha) {
-        if (((mState == ScrimState.AOD && mDozeParameters.getAlwaysOn())
-                || mState == ScrimState.PULSING) && mInFrontAlpha != alpha) {
+        if (mInFrontAlpha != alpha && shouldUpdateFrontScrimAlpha()) {
             mInFrontAlpha = alpha;
             updateScrims();
         }
@@ -530,6 +529,19 @@
         mState.PULSING.setAodFrontScrimAlpha(alpha);
     }
 
+    private boolean shouldUpdateFrontScrimAlpha() {
+        if (mState == ScrimState.AOD
+                && (mDozeParameters.getAlwaysOn() || mDockManager.isDocked())) {
+            return true;
+        }
+
+        if (mState == ScrimState.PULSING) {
+            return true;
+        }
+
+        return false;
+    }
+
     /**
      * If the lock screen sensor is active.
      */
@@ -1022,10 +1034,6 @@
 
         default void onCancelled() {
         }
-        /** Returns whether to timeout wallpaper or not. */
-        default boolean shouldTimeoutWallpaper() {
-            return false;
-        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 13055ff..40f8d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,6 +19,7 @@
 import android.graphics.Color;
 import android.os.Trace;
 
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -128,10 +129,11 @@
         @Override
         public void prepare(ScrimState previousState) {
             final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
+            final boolean isDocked = mDockManager.isDocked();
             mBlankScreen = mDisplayRequiresBlanking;
 
             mFrontTint = Color.BLACK;
-            mFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f;
+            mFrontAlpha = (alwaysOnEnabled || isDocked) ? mAodFrontScrimAlpha : 1f;
 
             mBehindTint = Color.BLACK;
             mBehindAlpha = ScrimController.TRANSPARENT;
@@ -258,6 +260,7 @@
     ScrimView mScrimForBubble;
 
     DozeParameters mDozeParameters;
+    DockManager mDockManager;
     boolean mDisplayRequiresBlanking;
     boolean mWallpaperSupportsAmbientMode;
     boolean mHasBackdrop;
@@ -267,12 +270,13 @@
     long mKeyguardFadingAwayDuration;
 
     public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
-            DozeParameters dozeParameters) {
+            DozeParameters dozeParameters, DockManager dockManager) {
         mScrimInFront = scrimInFront;
         mScrimBehind = scrimBehind;
         mScrimForBubble = scrimForBubble;
 
         mDozeParameters = dozeParameters;
+        mDockManager = dockManager;
         mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index f716443..c1328ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -75,10 +76,10 @@
     private PhoneStatusBarView mStatusBarView;
     private StatusBar mService;
     private DragDownHelper mDragDownHelper;
-    private boolean mSuppressingWakeUpGesture;
     private boolean mDoubleTapEnabled;
     private boolean mSingleTapEnabled;
     private boolean mExpandingBelowNotch;
+    private final DockManager mDockManager;
 
     private StatusBarWindowViewController(
             StatusBarWindowView view,
@@ -97,9 +98,11 @@
             SysuiStatusBarStateController statusBarStateController,
             DozeLog dozeLog,
             DozeParameters dozeParameters,
-            CommandQueue commandQueue) {
+            CommandQueue commandQueue,
+            DockManager dockManager) {
         mView = view;
         mFalsingManager = falsingManager;
+        mDockManager = dockManager;
 
         // TODO: create controller for NotificationPanelView
         NotificationPanelView notificationPanelView = new NotificationPanelView(
@@ -158,7 +161,7 @@
                 new GestureDetector.SimpleOnGestureListener() {
                     @Override
                     public boolean onSingleTapConfirmed(MotionEvent e) {
-                        if (mSingleTapEnabled && !mSuppressingWakeUpGesture) {
+                        if (mSingleTapEnabled && !mDockManager.isDocked()) {
                             mService.wakeUpIfDozing(
                                     SystemClock.uptimeMillis(), mView, "SINGLE_TAP");
                             return true;
@@ -243,7 +246,7 @@
 
             @Override
             public boolean shouldInterceptTouchEvent(MotionEvent ev) {
-                if (mService.isDozing() && !mService.isPulsing()) {
+                if (mService.isDozing() && !mService.isPulsing() && !mDockManager.isDocked()) {
                     // Capture all touch events in always-on.
                     return true;
                 }
@@ -445,10 +448,6 @@
         mDragDownHelper = dragDownHelper;
     }
 
-    public void suppressWakeUpGesture(boolean suppress) {
-        mSuppressingWakeUpGesture = suppress;
-    }
-
     /**
      * When we're launching an affordance, like double pressing power to open camera.
      */
@@ -495,6 +494,7 @@
         private final CommandQueue mCommandQueue;
         private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
         private final StatusBarWindowView mView;
+        private final DockManager mDockManager;
 
         @Inject
         public Builder(
@@ -513,7 +513,8 @@
                 DozeLog dozeLog,
                 DozeParameters dozeParameters,
                 CommandQueue commandQueue,
-                SuperStatusBarViewFactory superStatusBarViewFactory) {
+                SuperStatusBarViewFactory superStatusBarViewFactory,
+                DockManager dockManager) {
             mInjectionInflationController = injectionInflationController;
             mCoordinator = coordinator;
             mPulseExpansionHandler = pulseExpansionHandler;
@@ -530,8 +531,8 @@
             mDozeParameters = dozeParameters;
             mCommandQueue = commandQueue;
             mSuperStatusBarViewFactory = superStatusBarViewFactory;
-
             mView = mSuperStatusBarViewFactory.getStatusBarWindowView();
+            mDockManager = dockManager;
         }
 
         /**
@@ -563,7 +564,8 @@
                     mStatusBarStateController,
                     mDozeLog,
                     mDozeParameters,
-                    mCommandQueue);
+                    mCommandQueue,
+                    mDockManager);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index dba3b92..ddacc3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -185,6 +185,9 @@
             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             filter.addAction(Intent.ACTION_USER_SWITCHED);
 
+            // NOTE: This receiver could run before this method returns, as it's not dispatching
+            // on the main thread and BroadcastDispatcher may not need to register with Context.
+            // The receiver will return immediately if the view does not have a Handler yet.
             mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
                     Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
             Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
@@ -197,11 +200,9 @@
             mCurrentUserId = mCurrentUserTracker.getCurrentUserId();
         }
 
-        // NOTE: It's safe to do these after registering the receiver since the receiver always runs
-        // in the main thread, therefore the receiver can't run before this method returns.
-
         // The time zone may have changed while the receiver wasn't registered, so update the Time
         mCalendar = Calendar.getInstance(TimeZone.getDefault());
+        mClockFormatString = "";
 
         // Make sure we update to the current time
         updateClock();
@@ -227,10 +228,16 @@
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            // If the handler is null, it means we received a broadcast while the view has not
+            // finished being attached or in the process of being detached.
+            // In that case, do not post anything.
+            Handler handler = getHandler();
+            if (handler == null) return;
+
             String action = intent.getAction();
             if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                 String tz = intent.getStringExtra("time-zone");
-                getHandler().post(() -> {
+                handler.post(() -> {
                     mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
                     if (mClockFormat != null) {
                         mClockFormat.setTimeZone(mCalendar.getTimeZone());
@@ -238,14 +245,14 @@
                 });
             } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                 final Locale newLocale = getResources().getConfiguration().locale;
-                getHandler().post(() -> {
+                handler.post(() -> {
                     if (!newLocale.equals(mLocale)) {
                         mLocale = newLocale;
                         mClockFormatString = ""; // force refresh
                     }
                 });
             }
-            getHandler().post(() -> updateClock());
+            handler.post(() -> updateClock());
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index da01171..02c699f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -52,6 +52,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Slog;
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.annotations.GuardedBy;
@@ -1082,10 +1083,12 @@
         @Override
         public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
             addStream(token, "onRemoteUpdate");
+
             int stream = 0;
             synchronized (mRemoteStreams) {
                  stream = mRemoteStreams.get(token);
             }
+            Slog.d(TAG, "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume());
             boolean changed = mState.states.indexOfKey(stream) < 0;
             final StreamState ss = streamStateW(stream);
             ss.dynamic = true;
@@ -1101,8 +1104,7 @@
                 changed = true;
             }
             if (changed) {
-                if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
-                        + " of " + ss.levelMax);
+                Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level + " of " + ss.levelMax);
                 mCallbacks.onStateChanged(mState);
             }
         }
@@ -1115,11 +1117,13 @@
                 stream = mRemoteStreams.get(token);
             }
             final boolean showUI = shouldShowUI(flags);
+            Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI);
             boolean changed = updateActiveStreamW(stream);
             if (showUI) {
                 changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
             }
             if (changed) {
+                Slog.d(TAG, "onRemoteChanged: updatingState");
                 mCallbacks.onStateChanged(mState);
             }
             if (showUI) {
@@ -1132,7 +1136,7 @@
             int stream = 0;
             synchronized (mRemoteStreams) {
                 if (!mRemoteStreams.containsKey(token)) {
-                    if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+                    Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
                             + "aborting remote removed for token:" +  token.toString());
                     return;
                 }
@@ -1169,7 +1173,7 @@
             synchronized (mRemoteStreams) {
                 if (!mRemoteStreams.containsKey(token)) {
                     mRemoteStreams.put(token, mNextStream);
-                    if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
+                    Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
                             + " from token + " + token.toString());
                     mNextStream++;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
new file mode 100644
index 0000000..f3487fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -0,0 +1,199 @@
+/*
+ * 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 android.os.Handler;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.IDisplayWindowListener;
+import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayWindowRotationController;
+import android.view.WindowContainerTransaction;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
+ * frozen the screen, it will call into this class. This will then call all registered local
+ * controllers and give them a chance to queue up task changes to be applied synchronously with that
+ * rotation.
+ */
+@Singleton
+public class DisplayWindowController {
+    private final Handler mHandler;
+
+    private final ArrayList<OnDisplayWindowRotationController> mRotationControllers =
+            new ArrayList<>();
+    private final ArrayList<OnDisplayWindowRotationController> mTmpControllers = new ArrayList<>();
+
+    private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
+    private final ArrayList<DisplayWindowListener> mDisplayChangedListeners = new ArrayList<>();
+
+    private final IDisplayWindowRotationController mDisplayRotationController =
+            new IDisplayWindowRotationController.Stub() {
+                @Override
+                public void onRotateDisplay(int displayId, final int fromRotation,
+                        final int toRotation, IDisplayWindowRotationCallback callback) {
+                    mHandler.post(() -> {
+                        WindowContainerTransaction t = new WindowContainerTransaction();
+                        synchronized (mRotationControllers) {
+                            mTmpControllers.clear();
+                            // Make a local copy in case the handlers add/remove themselves.
+                            mTmpControllers.addAll(mRotationControllers);
+                        }
+                        for (OnDisplayWindowRotationController c : mTmpControllers) {
+                            c.onRotateDisplay(displayId, fromRotation, toRotation, t);
+                        }
+                        try {
+                            callback.continueRotateDisplay(toRotation, t);
+                        } catch (RemoteException e) {
+                        }
+                    });
+                }
+            };
+
+    private final IDisplayWindowListener mDisplayContainerListener =
+            new IDisplayWindowListener.Stub() {
+                @Override
+                public void onDisplayAdded(int displayId) {
+                    mHandler.post(() -> {
+                        synchronized (mDisplays) {
+                            if (mDisplays.get(displayId) != null) {
+                                return;
+                            }
+                            DisplayRecord record = new DisplayRecord();
+                            record.mDisplayId = displayId;
+                            mDisplays.put(displayId, record);
+                            for (DisplayWindowListener l : mDisplayChangedListeners) {
+                                l.onDisplayAdded(displayId);
+                            }
+                        }
+                    });
+                }
+
+                @Override
+                public void onDisplayRemoved(int displayId) {
+                    mHandler.post(() -> {
+                        synchronized (mDisplays) {
+                            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+                                mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
+                            }
+                            mDisplays.remove(displayId);
+                        }
+                    });
+                }
+            };
+
+    @Inject
+    public DisplayWindowController(@MainHandler Handler mainHandler) {
+        mHandler = mainHandler;
+        try {
+            WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
+                    mDisplayContainerListener);
+            WindowManagerGlobal.getWindowManagerService().setDisplayWindowRotationController(
+                    mDisplayRotationController);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Unable to register hierarchy listener");
+        }
+    }
+
+    /**
+     * Add a display window-container listener. It will get notified when displays are
+     * added/removed from the WM hierarchy.
+     */
+    public void addDisplayWindowListener(DisplayWindowListener listener) {
+        synchronized (mDisplays) {
+            if (mDisplayChangedListeners.contains(listener)) {
+                return;
+            }
+            mDisplayChangedListeners.add(listener);
+            for (int i = 0; i < mDisplays.size(); ++i) {
+                listener.onDisplayAdded(mDisplays.keyAt(i));
+            }
+        }
+    }
+
+    /**
+     * Remove a display window-container listener.
+     */
+    public void removeDisplayWindowListener(DisplayWindowListener listener) {
+        synchronized (mDisplays) {
+            mDisplayChangedListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Adds a display rotation controller.
+     */
+    public void addRotationController(OnDisplayWindowRotationController controller) {
+        synchronized (mRotationControllers) {
+            mRotationControllers.add(controller);
+        }
+    }
+
+    /**
+     * Removes a display rotation controller.
+     */
+    public void removeRotationController(OnDisplayWindowRotationController controller) {
+        synchronized (mRotationControllers) {
+            mRotationControllers.remove(controller);
+        }
+    }
+
+    private static class DisplayRecord {
+        int mDisplayId;
+    }
+
+    /**
+     * Gets notified when a display is added/removed to the WM hierarchy.
+     *
+     * @see IDisplayWindowListener
+     */
+    public interface DisplayWindowListener {
+        /**
+         * Called when a display has been added to the WM hierarchy.
+         */
+        void onDisplayAdded(int displayId);
+
+        /**
+         * Called when a display is removed.
+         */
+        void onDisplayRemoved(int displayId);
+    }
+
+    /**
+     * Give a controller a chance to queue up configuration changes to execute as part of a
+     * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
+     */
+    public interface OnDisplayWindowRotationController {
+        /**
+         * Called before the display is rotated. Contents of this method must run synchronously.
+         * @param displayId Id of display that is rotating.
+         * @param fromRotation starting rotation of the display.
+         * @param toRotation target rotation of the display (after rotating).
+         * @param t A task transaction to populate.
+         */
+        void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+                WindowContainerTransaction t);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 9bc962c..fe117fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -33,6 +33,7 @@
     private int mUid;
     private int mInitialPid;
     private Notification mNotification = new Notification();
+    private Notification.BubbleMetadata mBubbleMetadata;
     private UserHandle mUser = UserHandle.of(0);
     private String mOverrideGroupKey;
     private long mPostTime;
@@ -54,6 +55,9 @@
     }
 
     public StatusBarNotification build() {
+        if (mBubbleMetadata != null) {
+            mNotification.setBubbleMetadata(mBubbleMetadata);
+        }
         return new StatusBarNotification(
                 mPkg,
                 mOpPkg,
@@ -116,4 +120,9 @@
         mPostTime = postTime;
         return this;
     }
+
+    public SbnBuilder setBubbleMetadata(Notification.BubbleMetadata data) {
+        mBubbleMetadata = data;
+        return this;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index bc616c5..0b123fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -321,6 +321,7 @@
                 .build();
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+        NotificationEntry entry = row.getEntry();
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
@@ -331,7 +332,7 @@
                 eq(statusBarNotification.getPackageName()),
                 any(NotificationChannel.class),
                 anySet(),
-                eq(statusBarNotification),
+                eq(entry),
                 any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -352,6 +353,7 @@
                 .build();
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+        NotificationEntry entry = row.getEntry();
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
@@ -362,7 +364,7 @@
                 eq(statusBarNotification.getPackageName()),
                 any(NotificationChannel.class),
                 anySet(),
-                eq(statusBarNotification),
+                eq(entry),
                 any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -385,6 +387,7 @@
         row.getEntry().setIsHighPriority(true);
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+        NotificationEntry entry = row.getEntry();
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
@@ -395,7 +398,7 @@
                 eq(statusBarNotification.getPackageName()),
                 any(NotificationChannel.class),
                 anySet(),
-                eq(statusBarNotification),
+                eq(entry),
                 any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -416,6 +419,8 @@
                 .build();
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+        NotificationEntry entry = row.getEntry();
+
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -427,7 +432,7 @@
                 eq(statusBarNotification.getPackageName()),
                 any(NotificationChannel.class),
                 anySet(),
-                eq(statusBarNotification),
+                eq(entry),
                 any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -448,6 +453,7 @@
                 .build();
         when(row.getIsNonblockable()).thenReturn(false);
         StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+        NotificationEntry entry = row.getEntry();
 
         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
 
@@ -458,7 +464,7 @@
                 eq(statusBarNotification.getPackageName()),
                 any(NotificationChannel.class),
                 anySet(),
-                eq(statusBarNotification),
+                eq(entry),
                 any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 703adf7..bdca7ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static android.app.Notification.FLAG_BUBBLE;
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -49,10 +50,13 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
+import android.app.PendingIntent;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -72,7 +76,12 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.bubbles.BubblesTestActivity;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.After;
 import org.junit.Before;
@@ -106,6 +115,9 @@
     private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>();
     private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>();
     private StatusBarNotification mSbn;
+    private NotificationEntry mEntry;
+    private StatusBarNotification mBubbleSbn;
+    private NotificationEntry mBubbleEntry;
 
     @Rule
     public MockitoRule mockito = MockitoJUnit.rule();
@@ -119,6 +131,8 @@
     private NotificationBlockingHelperManager mBlockingHelperManager;
     @Mock
     private VisualStabilityManager mVisualStabilityManager;
+    @Mock
+    private BubbleController mBubbleController;
 
     @Before
     public void setUp() throws Exception {
@@ -126,13 +140,18 @@
                 NotificationBlockingHelperManager.class,
                 mBlockingHelperManager);
         mTestableLooper = TestableLooper.get(this);
+
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+        mDependency.injectTestDependency(BubbleController.class, mBubbleController);
         // Inflate the layout
         final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
         mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
                 null);
         mNotificationInfo.setGutsParent(mock(NotificationGuts.class));
+        // Our view is never attached to a window so the View#post methods in NotificationInfo never
+        // get called. Setting this will skip the post and do the action immediately.
+        mNotificationInfo.mSkipPost = true;
 
         // PackageManager must return a packageInfo and applicationInfo.
         final PackageInfo packageInfo = new PackageInfo();
@@ -164,6 +183,16 @@
         mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
+        mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent(mContext, BubblesTestActivity.class), 0);
+        mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata(
+                new Notification.BubbleMetadata.Builder()
+                        .setIntent(bubbleIntent)
+                        .setIcon(Icon.createWithResource(mContext, R.drawable.android)).build())
+                .build();
+        mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build();
 
         Settings.Secure.putInt(mContext.getContentResolver(),
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
@@ -182,17 +211,6 @@
                 () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
     }
 
-    private void ensureNoUndoButton() {
-        PollingCheck.waitFor(1000,
-                () -> GONE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility()
-                        && !mNotificationInfo.isAnimating());
-    }
-
-    private void waitForStopButton() {
-        PollingCheck.waitFor(1000,
-                () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
-    }
-
     @Test
     public void testBindNotification_SetsTextApplicationName() throws Exception {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -203,7 +221,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -228,7 +246,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -249,7 +267,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -273,6 +291,7 @@
                 applicationInfo);
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
 
+        NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
         mNotificationInfo.bindNotification(
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -280,7 +299,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                entry,
                 null,
                 null,
                 null,
@@ -304,7 +323,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -331,7 +350,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -353,7 +372,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -374,7 +393,7 @@
                 TEST_PACKAGE_NAME,
                 mDefaultNotificationChannel,
                 mDefaultNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -399,7 +418,7 @@
                 TEST_PACKAGE_NAME,
                 mDefaultNotificationChannel,
                 mDefaultNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -420,7 +439,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -441,7 +460,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 mock(NotificationInfo.OnSettingsClickListener.class),
                 null,
@@ -468,7 +487,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
@@ -495,7 +514,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -517,7 +536,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
@@ -540,7 +559,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -555,7 +574,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 (View v, NotificationChannel c, int appUid) -> { },
                 null,
@@ -576,7 +595,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -600,7 +619,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -625,7 +644,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -647,7 +666,7 @@
                 mVisualStabilityManager,
                 TEST_PACKAGE_NAME, mNotificationChannel,
                 createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
-                mSbn,
+                mEntry,
                 null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(null, c);
@@ -675,7 +694,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -698,7 +717,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -721,7 +740,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -738,6 +757,202 @@
     }
 
     @Test
+    public void testBindNotification_alertIsSelected() throws Exception {
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+        assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
+    }
+
+    @Test
+    public void testBindNotification_silenceIsSelected() throws Exception {
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                false);
+        assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
+    }
+
+    @Test
+    public void testBindNotification_bubbleIsSelected() throws Exception {
+        mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+
+        View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+        assertEquals(View.VISIBLE, bubbleView.getVisibility());
+        assertTrue(bubbleView.isSelected());
+    }
+
+    @Test
+    public void testBindNotification_whenCanBubble() throws Exception {
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+
+        View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+        assertEquals(View.VISIBLE, bubbleView.getVisibility());
+        assertFalse(bubbleView.isSelected());
+    }
+
+    @Test
+    public void testBindNotification_whenCantBubble() throws Exception {
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+        View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+        assertEquals(View.GONE, bubbleView.getVisibility());
+    }
+
+    @Test
+    public void testBubble_promotesBubble() throws Exception {
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+
+        assertFalse(mBubbleEntry.isBubble());
+
+        // Promote it
+        mNotificationInfo.findViewById(R.id.bubble).performClick();
+        mNotificationInfo.findViewById(R.id.done).performClick();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        verify(mBubbleController, times(1)).onUserCreatedBubbleFromNotification(mBubbleEntry);
+    }
+
+    @Test
+    public void testAlert_demotesBubble() throws Exception {
+        mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+
+        assertTrue(mBubbleEntry.isBubble());
+
+        // Demote it
+        mNotificationInfo.findViewById(R.id.alert).performClick();
+        mNotificationInfo.findViewById(R.id.done).performClick();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry);
+    }
+
+    @Test
+    public void testSilence_demotesBubble() throws Exception {
+        mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mVisualStabilityManager,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mBubbleEntry,
+                null,
+                null,
+                null,
+                true,
+                false,
+                IMPORTANCE_DEFAULT,
+                true);
+
+        assertTrue(mBubbleEntry.isBubble());
+
+        // Demote it
+        mNotificationInfo.findViewById(R.id.silence).performClick();
+        mNotificationInfo.findViewById(R.id.done).performClick();
+        mNotificationInfo.handleCloseControls(true, false);
+
+        verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry);
+    }
+
+    @Test
     public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
         mNotificationInfo.bindNotification(
                 mMockPackageManager,
@@ -746,7 +961,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -769,7 +984,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -795,7 +1010,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -821,7 +1036,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -848,7 +1063,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -878,7 +1093,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel /* notificationChannel */,
                 createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mSbn,
+                mEntry,
                 listener /* checkSaveListener */,
                 null /* onSettingsClick */,
                 null /* onAppSettingsClick */,
@@ -917,7 +1132,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel /* notificationChannel */,
                 createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mSbn,
+                mEntry,
                 listener /* checkSaveListener */,
                 null /* onSettingsClick */,
                 null /* onAppSettingsClick */,
@@ -945,7 +1160,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel /* notificationChannel */,
                 createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mSbn,
+                mEntry,
                 listener /* checkSaveListener */,
                 null /* onSettingsClick */,
                 null /* onAppSettingsClick */,
@@ -970,7 +1185,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet /* numChannels */,
-                mSbn,
+                mEntry,
                 null /* checkSaveListener */,
                 null /* onSettingsClick */,
                 null /* onAppSettingsClick */,
@@ -999,7 +1214,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet /* numChannels */,
-                mSbn,
+                mEntry,
                 null /* checkSaveListener */,
                 null /* onSettingsClick */,
                 null /* onAppSettingsClick */,
@@ -1033,7 +1248,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1064,7 +1279,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1094,7 +1309,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1127,7 +1342,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1161,7 +1376,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1195,7 +1410,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1232,7 +1447,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1268,7 +1483,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1295,7 +1510,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1325,7 +1540,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1358,7 +1573,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 null,
                 null,
                 null,
@@ -1386,7 +1601,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                     saveImportance.run();
                 },
@@ -1421,7 +1636,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                     saveImportance.run();
                 },
@@ -1449,7 +1664,7 @@
                 TEST_PACKAGE_NAME,
                 mNotificationChannel,
                 mNotificationChannelSet,
-                mSbn,
+                mEntry,
                 (Runnable saveImportance, StatusBarNotification sbn) -> {
                     saveImportance.run();
                 },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 5af1e14..105dbad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -158,26 +158,6 @@
         verify(mStatusBar).updateScrimController();
     }
 
-
-    @Test
-    public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() {
-        // Keep track of callback to be able to stop the pulse
-        final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
-        doAnswer(invocation -> {
-            pulseCallback[0] = invocation.getArgument(0);
-            return null;
-        }).when(mDozeScrimController).pulse(any(), anyInt());
-
-        // Starting a pulse while docking should suppress wakeup gesture
-        mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
-                DozeEvent.PULSE_REASON_DOCKING);
-        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true));
-
-        // Ending a pulse should restore wakeup gesture
-        pulseCallback[0].onPulseFinished();
-        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false));
-    }
-
     @Test
     public void testPulseWhileDozing_notifyAuthInterrupt() {
         HashSet<Integer> reasonsWantingAuth = new HashSet<>(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 85c247e..4d6ff1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -50,6 +50,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -101,6 +102,8 @@
     KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
     private SysuiColorExtractor mSysuiColorExtractor;
+    @Mock
+    private DockManager mDockManager;
 
 
     private static class AnimatorListener implements Animator.AnimatorListener {
@@ -210,10 +213,13 @@
 
         when(mSysuiColorExtractor.getNeutralColors()).thenReturn(new GradientColors());
 
+        when(mDockManager.isDocked()).thenReturn(false);
+
         mScrimController = new ScrimController(mLightBarController,
                 mDozeParamenters, mAlarmManager, mKeyguardStateController,
                 mResources, mDelayedWakeLockBuilder,
-                new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor);
+                new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
+                mDockManager);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -372,6 +378,45 @@
     }
 
     @Test
+    public void transitionToAod_afterDocked_ignoresAlwaysOnAndUpdatesFrontAlpha() {
+        // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        mScrimController.setAodFrontScrimAlpha(0.5f);
+        finishAnimationsImmediately();
+
+        assertScrimAlpha(TRANSPARENT /* front */,
+                SEMI_TRANSPARENT /* back */,
+                TRANSPARENT /* bubble */);
+
+        // ... and doesn't take effect when disabled always_on
+        mAlwaysOnEnabled = false;
+        mScrimController.transitionTo(ScrimState.AOD);
+        finishAnimationsImmediately();
+        assertScrimAlpha(OPAQUE /* front */,
+                OPAQUE /* back */,
+                TRANSPARENT /* bubble */);
+
+        // ... but will take effect after docked
+        when(mDockManager.isDocked()).thenReturn(true);
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        mScrimController.setAodFrontScrimAlpha(0.5f);
+        mScrimController.transitionTo(ScrimState.AOD);
+
+        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
+                OPAQUE /* back */,
+                TRANSPARENT /* bubble */);
+
+        // ... and that if we set it while we're in AOD, it does take immediate effect after docked.
+        mScrimController.setAodFrontScrimAlpha(1f);
+        assertScrimAlpha(OPAQUE /* front */,
+                OPAQUE /* back */,
+                TRANSPARENT /* bubble */);
+
+        // Reset value since enums are static.
+        mScrimController.setAodFrontScrimAlpha(0f);
+    }
+
+    @Test
     public void transitionToPulsing_withFrontAlphaUpdates() {
         // Pre-condition
         // Need to go to AoD first because PULSING doesn't change
@@ -715,38 +760,6 @@
     }
 
     @Test
-    public void transitionToPulsing_withTimeoutWallpaperCallback_willHideWallpaper() {
-        mScrimController.setWallpaperSupportsAmbientMode(true);
-
-        mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
-            @Override
-            public boolean shouldTimeoutWallpaper() {
-                return true;
-            }
-        });
-
-        verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
-    }
-
-    @Test
-    public void transitionToPulsing_withDefaultCallback_wontHideWallpaper() {
-        mScrimController.setWallpaperSupportsAmbientMode(true);
-
-        mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {});
-
-        verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
-    }
-
-    @Test
-    public void transitionToPulsing_withoutCallback_wontHideWallpaper() {
-        mScrimController.setWallpaperSupportsAmbientMode(true);
-
-        mScrimController.transitionTo(ScrimState.PULSING);
-
-        verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
-    }
-
-    @Test
     public void testConservesExpansionOpacityAfterTransition() {
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         mScrimController.setPanelExpansion(0.5f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index bf81325..4d4e9ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -29,6 +29,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
@@ -74,6 +75,7 @@
     @Mock private DozeLog mDozeLog;
     @Mock private DozeParameters mDozeParameters;
     @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    @Mock private DockManager mDockManager;
 
     @Before
     public void setUp() {
@@ -85,6 +87,7 @@
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
         when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
+        when(mDockManager.isDocked()).thenReturn(false);
 
         mController = new StatusBarWindowViewController.Builder(
                 new InjectionInflationController(
@@ -103,7 +106,8 @@
                 mDozeLog,
                 mDozeParameters,
                 new CommandQueue(mContext),
-                mSuperStatusBarViewFactory)
+                mSuperStatusBarViewFactory,
+                mDockManager)
                 .setShadeController(mShadeController)
                 .build();
         mController.setService(mStatusBar);
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 56020cd..748eb40 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -24,3 +24,27 @@
     certificate: "platform",
     privileged: false,
 }
+
+android_test {
+    name: "WallpaperBackupAgentTests",
+    manifest: "test/AndroidManifest.xml",
+    test_config: "test/AndroidTest.xml",
+    srcs: [
+        // Include the app source code because the app runs as the system user on-device.
+        "src/**/*.java",
+        "test/src/**/*.java"
+    ],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+    ],
+    certificate: "platform",
+    platform_apis: true,
+    test_suites: ["device-tests"]
+}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index da90189..1c2c640 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -39,6 +39,8 @@
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -89,7 +91,7 @@
             Slog.v(TAG, "onCreate()");
         }
 
-        File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+        File wallpaperDir = getWallpaperDir();
         mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
         mWallpaperFile = new File(wallpaperDir, WALLPAPER);
         mLockWallpaperFile = new File(wallpaperDir, WALLPAPER_LOCK);
@@ -102,6 +104,11 @@
         }
     }
 
+    @VisibleForTesting
+    protected File getWallpaperDir() {
+        return Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+    }
+
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
         // To avoid data duplication and disk churn, use links as the stage.
@@ -119,7 +126,7 @@
                 FileOutputStream touch = new FileOutputStream(empty);
                 touch.close();
             }
-            fullBackupFile(empty, data);
+            backupFile(empty, data);
 
             SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
             final int lastSysGeneration = prefs.getInt(SYSTEM_GENERATION, -1);
@@ -155,7 +162,7 @@
                     FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
                 }
                 if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
-                fullBackupFile(infoStage, data);
+                backupFile(infoStage, data);
             }
             if (sysEligible && mWallpaperFile.exists()) {
                 if (sysChanged || !imageStage.exists()) {
@@ -163,7 +170,7 @@
                     FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
                 }
                 if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
-                fullBackupFile(imageStage, data);
+                backupFile(imageStage, data);
                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
             }
 
@@ -174,7 +181,7 @@
                     FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
                 }
                 if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
-                fullBackupFile(lockImageStage, data);
+                backupFile(lockImageStage, data);
                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
             }
         } catch (Exception e) {
@@ -189,6 +196,12 @@
         }
     }
 
+    @VisibleForTesting
+    // fullBackupFile is final, so we intercept backups here in tests.
+    protected void backupFile(File file, FullBackupDataOutput data) {
+        fullBackupFile(file, data);
+    }
+
     @Override
     public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
         if (DEBUG) {
diff --git a/packages/WallpaperBackup/test/AndroidManifest.xml b/packages/WallpaperBackup/test/AndroidManifest.xml
new file mode 100644
index 0000000..44ab1b6
--- /dev/null
+++ b/packages/WallpaperBackup/test/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.wallpaperbackup.tests">
+
+    <application android:label="WallpaperBackup Tests">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.wallpaperbackup.tests"
+                     android:label="WallpaperBackup Tests"/>
+</manifest>
+
diff --git a/packages/WallpaperBackup/test/AndroidTest.xml b/packages/WallpaperBackup/test/AndroidTest.xml
new file mode 100644
index 0000000..f2e7782
--- /dev/null
+++ b/packages/WallpaperBackup/test/AndroidTest.xml
@@ -0,0 +1,27 @@
+<!-- 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.
+-->
+<configuration description="Runs sample instrumentation test.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="WallpaperBackupAgentTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="WallpaperBackupAgentTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.wallpaperbackup.tests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
new file mode 100644
index 0000000..46a7dfe
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.wallpaperbackup.tests;
+
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.WallpaperManager;
+import android.app.backup.FullBackupDataOutput;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.wallpaperbackup.WallpaperBackupAgent;
+import com.android.wallpaperbackup.utils.ContextWithServiceOverrides;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class WallpaperBackupAgentTest {
+    private static final String SYSTEM_GENERATION = "system_gen";
+    private static final String LOCK_GENERATION = "lock_gen";
+
+    @Mock private FullBackupDataOutput mOutput;
+    @Mock private WallpaperManager mWallpaperManager;
+    @Mock private SharedPreferences mSharedPreferences;
+
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    private ContextWithServiceOverrides mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
+        mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
+        mContext.setSharedPreferencesOverride(mSharedPreferences);
+    }
+
+    @Test
+    public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException {
+        WallpaperBackupAgent wallpaperBackupAgent = new WallpaperBackupAgent();
+        initialiseAgent(wallpaperBackupAgent);
+
+        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(1);
+        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(1);
+        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
+        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+
+        wallpaperBackupAgent.onFullBackup(mOutput);
+
+        verify(mOutput); // Backup of empty file only
+    }
+
+    @Test
+    public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()
+            throws IOException {
+        // Create a system wallpaper file
+        mTemporaryFolder.newFile("wallpaper_orig");
+        // Create stageing file to simulate he wallpaper being ready to back up
+        new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
+
+        WallpaperBackupAgent wallpaperBackupAgent =
+                new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
+        initialiseAgent(wallpaperBackupAgent);
+
+        SharedPreferences.Editor preferenceEditor = mock(SharedPreferences.Editor.class);
+
+        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(2);
+        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(1);
+        when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
+        when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
+        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
+        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+        when(mSharedPreferences.edit()).thenReturn(preferenceEditor);
+        when(preferenceEditor.putInt(eq(SYSTEM_GENERATION), eq(2))).thenReturn(preferenceEditor);
+
+        wallpaperBackupAgent.onFullBackup(mOutput);
+
+        verify(preferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(2));
+    }
+
+    private void initialiseAgent(WallpaperBackupAgent agent) {
+        agent.attach(mContext);
+        agent.onCreate();
+    }
+
+    private static class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
+        File mWallpaperBaseDirectory;
+        List<File> mBackedUpFiles = new ArrayList();
+
+        IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
+            mWallpaperBaseDirectory = wallpaperBaseDirectory;
+        }
+
+        @Override
+        protected File getWallpaperDir() {
+            return mWallpaperBaseDirectory;
+        }
+
+        @Override
+        protected void backupFile(File file, FullBackupDataOutput data) {
+            mBackedUpFiles.add(file);
+        }
+    }
+}
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java
new file mode 100644
index 0000000..df5d74a
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java
@@ -0,0 +1,64 @@
+/*
+ * 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.wallpaperbackup.utils;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ContextWithServiceOverrides extends ContextWrapper {
+    private static final String TAG = "ContextWithOverrides";
+
+    private Map<String, Object> mInjectedSystemServices = new HashMap<>();
+    private SharedPreferences mSharedPreferencesOverride;
+
+    public ContextWithServiceOverrides(Context base) {
+        super(base);
+    }
+
+    public <S> void injectSystemService(Class<S> cls, S service) {
+        final String name = getSystemServiceName(cls);
+        mInjectedSystemServices.put(name, service);
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return this;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        if (mInjectedSystemServices.containsKey(name)) {
+            return mInjectedSystemServices.get(name);
+        }
+        return super.getSystemService(name);
+    }
+
+    public void setSharedPreferencesOverride(SharedPreferences override) {
+        mSharedPreferencesOverride = override;
+    }
+
+    @Override
+    public SharedPreferences getSharedPreferences(String name, int mode) {
+        return mSharedPreferencesOverride == null
+                ? super.getSharedPreferences(name, mode)
+                : mSharedPreferencesOverride;
+    }
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3916f0d..dcc690f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -141,6 +141,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.storage.AppFuseBridge;
 import com.android.server.storage.StorageSessionController;
+import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
 
@@ -196,9 +197,6 @@
     private static final String ZRAM_ENABLED_PROPERTY =
             "persist.sys.zram_enabled";
 
-    private static final boolean IS_FUSE_ENABLED =
-            SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);
-
     private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
 
     /**
@@ -350,6 +348,10 @@
     @GuardedBy("mLock")
     private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
 
+    /** Map from volume ID to latches */
+    @GuardedBy("mLock")
+    private ArrayMap<String, CountDownLatch> mFuseVolumeReadyLatches = new ArrayMap<>();
+
     @GuardedBy("mLock")
     private IPackageMoveObserver mMoveCallback;
     @GuardedBy("mLock")
@@ -419,7 +421,7 @@
     private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
-            return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
+            return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL + ";" + 0);
         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
             return storage.getPrimaryPhysicalVolume();
         } else {
@@ -462,6 +464,17 @@
         }
     }
 
+    private CountDownLatch findOrCreateFuseVolumeReadyLatch(String volId) {
+        synchronized (mLock) {
+            CountDownLatch latch = mFuseVolumeReadyLatches.get(volId);
+            if (latch == null) {
+                latch = new CountDownLatch(1);
+                mFuseVolumeReadyLatches.put(volId, latch);
+            }
+            return latch;
+        }
+    }
+
     /** List of crypto types.
       * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
       * corresponding commands in CommandListener.cpp */
@@ -514,6 +527,8 @@
     // Not guarded by a lock.
     private final StorageSessionController mStorageSessionController;
 
+    private final boolean mIsFuseEnabled;
+
     class ObbState implements IBinder.DeathRecipient {
         public ObbState(String rawPath, String canonicalPath, int callingUid,
                 IObbActionListener token, int nonce, String volId) {
@@ -597,6 +612,7 @@
     private static final int H_ABORT_IDLE_MAINT = 12;
     private static final int H_BOOT_COMPLETED = 13;
     private static final int H_COMPLETE_UNLOCK_USER = 14;
+    private static final int H_VOLUME_READY = 15;
 
     class StorageManagerServiceHandler extends Handler {
         public StorageManagerServiceHandler(Looper looper) {
@@ -657,6 +673,22 @@
                     }
                     break;
                 }
+                case H_VOLUME_READY: {
+                    final VolumeInfo vol = (VolumeInfo) msg.obj;
+                    try {
+                        mStorageSessionController.onVolumeReady(vol);
+
+                        synchronized (mLock) {
+                            CountDownLatch latch = mFuseVolumeReadyLatches.remove(vol.id);
+                            if (latch != null) {
+                                latch.countDown();
+                            }
+                        }
+                    } catch (IllegalStateException | ExternalStorageServiceException e) {
+                        Slog.i(TAG, "Failed to initialise volume " + vol, e);
+                    }
+                    break;
+                }
                 case H_VOLUME_MOUNT: {
                     final VolumeInfo vol = (VolumeInfo) msg.obj;
                     if (isMountDisallowed(vol)) {
@@ -664,19 +696,12 @@
                         break;
                     }
 
-                    // TODO(b/135341433): Remove paranoid logging when FUSE is stable
-                    Slog.i(TAG, "Mounting volume " + vol);
-                    // TODO(b/135341433): Update to use new vold API that gets or mounts fuse fd
-                    // Ensure that we can pass user of a volume to the new API
-                    mStorageSessionController.onVolumeMounted(mCurrentUserId, mount(vol), vol);
-                    Slog.i(TAG, "Mounted volume " + vol);
-
+                    mount(vol);
                     break;
                 }
                 case H_VOLUME_UNMOUNT: {
                     final VolumeInfo vol = (VolumeInfo) msg.obj;
                     unmount(vol);
-                    mStorageSessionController.onVolumeUnmounted(mCurrentUserId, vol);
                     break;
                 }
                 case H_VOLUME_BROADCAST: {
@@ -757,7 +782,6 @@
                         }
                     }
                     mVold.onUserRemoved(userId);
-                    mStorageSessionController.onUserRemoved(userId);
                 }
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
@@ -978,7 +1002,12 @@
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mBootCompleted && mDaemonConnected) {
             final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
-            killMediaProvider(users);
+
+            if (mIsFuseEnabled) {
+                mStorageSessionController.onReset(mVold, mHandler);
+            } else {
+                killMediaProvider(users);
+            }
 
             final int[] systemUnlockedUsers;
             synchronized (mLock) {
@@ -992,7 +1021,7 @@
 
             try {
                 // TODO(b/135341433): Remove paranoid logging when FUSE is stable
-                Slog.i(TAG, "Resetting vold");
+                Slog.i(TAG, "Resetting vold...");
                 mVold.reset();
                 Slog.i(TAG, "Reset vold");
 
@@ -1019,7 +1048,7 @@
         // staging area is ready so it's ready for zygote-forked apps to
         // bind mount against.
         try {
-            mStorageSessionController.onUserStarted(userId);
+            mStorageSessionController.onUnlockUser(userId);
             mVold.onUserStarted(userId);
             mStoraged.onUserStarted(userId);
         } catch (Exception e) {
@@ -1201,10 +1230,12 @@
         }
 
         @Override
-        public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
+        public void onVolumeCreated(String volId, int type, String diskId, String partGuid,
+                int userId) {
             synchronized (mLock) {
                 final DiskInfo disk = mDisks.get(diskId);
                 final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
+                vol.mountUserId = userId;
                 mVolumes.put(volId, vol);
                 onVolumeCreatedLocked(vol);
             }
@@ -1258,8 +1289,13 @@
 
         @Override
         public void onVolumeDestroyed(String volId) {
+            VolumeInfo vol = null;
             synchronized (mLock) {
-                mVolumes.remove(volId);
+                vol = mVolumes.remove(volId);
+            }
+
+            if (vol != null) {
+                mStorageSessionController.onVolumeRemove(vol);
             }
         }
     };
@@ -1395,6 +1431,13 @@
             writeSettingsLocked();
         }
 
+        if (mIsFuseEnabled && newState == VolumeInfo.STATE_MOUNTED
+                && (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_EMULATED)) {
+            Slog.i(TAG, "Initialising volume " + vol + " ...");
+            // TODO(b/144275217): Delay broadcasts till mount is really ready
+            mHandler.obtainMessage(H_VOLUME_READY, vol).sendToTarget();
+        }
+
         mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
 
         // Do not broadcast before boot has completed to avoid launching the
@@ -1546,13 +1589,12 @@
         // 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);
         mContext = context;
         mResolver = mContext.getContentResolver();
-
         mCallbacks = new Callbacks(FgThread.get().getLooper());
         mLockPatternUtils = new LockPatternUtils(mContext);
 
@@ -1563,11 +1605,7 @@
         // Add OBB Action Handler to StorageManagerService thread.
         mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
 
-        mStorageSessionController = new StorageSessionController(mContext,
-                userId -> {
-                    Slog.i(TAG, "Storage session ended for user: " + userId + ". Resetting...");
-                    mHandler.obtainMessage(H_RESET).sendToTarget();
-                });
+        mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
 
         // Initialize the last-fstrim tracking if necessary
         File dataDir = Environment.getDataDirectory();
@@ -1873,21 +1911,36 @@
         if (isMountDisallowed(vol)) {
             throw new SecurityException("Mounting " + volId + " restricted by policy");
         }
+
+        CountDownLatch latch = null;
+        if (mIsFuseEnabled && StorageSessionController.isEmulatedOrPublic(vol)) {
+            latch = findOrCreateFuseVolumeReadyLatch(volId);
+        }
+
         mount(vol);
+
+        if (latch != null) {
+            try {
+                waitForLatch(latch, "mount " + volId, 3 * DateUtils.MINUTE_IN_MILLIS);
+            } catch (TimeoutException e) {
+                Slog.wtf(TAG, e);
+            } finally {
+                synchronized (mLock) {
+                    mFuseVolumeReadyLatches.remove(volId);
+                }
+            }
+        }
     }
 
-    private FileDescriptor mount(VolumeInfo vol) {
+    private void mount(VolumeInfo vol) {
         try {
-            // TODO(b/135341433): Now, emulated (and private?) volumes are shared across users
-            // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which
-            // requires a valid user to mount a volume. Create individual volumes per user in vold
-            // and remove this property check
-            int userId = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false)
-                    ? mCurrentUserId : vol.mountUserId;
-            return mVold.mount(vol.id, vol.mountFlags, userId);
+            // TODO(b/135341433): Remove paranoid logging when FUSE is stable
+            Slog.i(TAG, "Mounting volume " + vol);
+            FileDescriptor fd = mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
+            Slog.i(TAG, "Mounted volume " + vol);
+            mStorageSessionController.onVolumeMount(fd, vol);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
-            return null;
         }
     }
 
@@ -1902,6 +1955,7 @@
     private void unmount(VolumeInfo vol) {
         try {
             mVold.unmount(vol.id);
+            mStorageSessionController.onVolumeUnmount(vol);
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -3040,6 +3094,14 @@
 
     @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);
@@ -3121,8 +3183,12 @@
                 switch (vol.getType()) {
                     case VolumeInfo.TYPE_PUBLIC:
                     case VolumeInfo.TYPE_STUB:
-                    case VolumeInfo.TYPE_EMULATED:
                         break;
+                    case VolumeInfo.TYPE_EMULATED:
+                        if (vol.getMountUserId() == userId) {
+                            break;
+                        }
+                        // Skip if emulated volume not for userId
                     default:
                         continue;
                 }
@@ -3711,7 +3777,7 @@
                 return Zygote.MOUNT_EXTERNAL_NONE;
             }
 
-            if (IS_FUSE_ENABLED && packageName.equals(mMediaStoreAuthorityPackageName)) {
+            if (mIsFuseEnabled && packageName.equals(mMediaStoreAuthorityPackageName)) {
                 // Determine if caller requires pass_through mount
                 return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
             }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index a7b9051..dcef998 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -150,10 +150,6 @@
                 mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
                 mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
                 mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
-                mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
-                mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
-                mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
-                mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
                 mInfo.rotation = mOverrideDisplayInfo.rotation;
                 mInfo.displayCutout = mOverrideDisplayInfo.displayCutout;
                 mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
diff --git a/services/core/java/com/android/server/integrity/model/AtomicFormula.java b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
index a757528..70ab98c 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
@@ -177,6 +177,14 @@
             dest.writeInt(mOperator);
         }
 
+        public int getValue() {
+            return mValue;
+        }
+
+        public int getOperator() {
+            return mOperator;
+        }
+
         private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
             switch (getKey()) {
                 case VERSION_CODE:
@@ -271,6 +279,10 @@
             dest.writeStringNoHelper(mValue);
         }
 
+        public String getValue() {
+            return mValue;
+        }
+
         private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
             switch (getKey()) {
                 case PACKAGE_NAME:
@@ -367,6 +379,10 @@
             dest.writeByte((byte) (mValue ? 1 : 0));
         }
 
+        public boolean getValue() {
+            return mValue;
+        }
+
         private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
             switch (getKey()) {
                 case PRE_INSTALLED:
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParseException.java b/services/core/java/com/android/server/integrity/parser/RuleParseException.java
new file mode 100644
index 0000000..c0f36a6
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleParseException.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.server.integrity.parser;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when rule parsing fails.
+ */
+public class RuleParseException extends Exception {
+    public RuleParseException(@NonNull String message) {
+        super(message);
+    }
+
+    public RuleParseException(@NonNull String message, @NonNull Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index bfffc70..08e0a5d 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -25,8 +25,8 @@
 public interface RuleParser {
 
     /** Parse rules from a string. */
-    List<Rule> parse(String ruleText);
+    List<Rule> parse(String ruleText) throws RuleParseException;
 
     /** Parse rules from an input stream. */
-    List<Rule> parse(InputStream inputStream);
+    List<Rule> parse(InputStream inputStream) throws RuleParseException;
 }
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index bf31bb2..23d0b40 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -16,9 +16,11 @@
 
 package com.android.server.integrity.parser;
 
-import android.util.Slog;
 import android.util.Xml;
 
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
 import com.android.server.integrity.model.Rule;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -38,49 +40,56 @@
 
     public static final String TAG = "RuleXmlParser";
 
-    private static final String RULE_LIST_TAG = "RuleList";
-    private static final String RULE_TAG = "Rule";
+    // TODO: Use XML attributes
+    private static final String RULE_LIST_TAG = "RL";
+    private static final String RULE_TAG = "R";
+    private static final String OPEN_FORMULA_TAG = "OF";
+    private static final String ATOMIC_FORMULA_TAG = "AF";
+    private static final String EFFECT_TAG = "E";
+    private static final String KEY_TAG = "K";
+    private static final String OPERATOR_TAG = "O";
+    private static final String VALUE_TAG = "V";
+    private static final String CONNECTOR_TAG = "C";
 
     @Override
-    public List<Rule> parse(String ruleText) {
+    public List<Rule> parse(String ruleText) throws RuleParseException {
         try {
             XmlPullParser xmlPullParser = Xml.newPullParser();
             xmlPullParser.setInput(new StringReader(ruleText));
             return parseRules(xmlPullParser);
-        } catch (XmlPullParserException | IOException e) {
-            Slog.e(TAG, String.format("Unable to read rules from string: %s", ruleText), e);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
         }
-        return null;
     }
 
     @Override
-    public List<Rule> parse(InputStream inputStream) {
+    public List<Rule> parse(InputStream inputStream) throws RuleParseException {
         try {
             XmlPullParser xmlPullParser = Xml.newPullParser();
             xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
             return parseRules(xmlPullParser);
-        } catch (XmlPullParserException | IOException e) {
-            Slog.e(TAG, "Unable to read rules from stream", e);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
         }
-        return null;
     }
 
-    private List<Rule> parseRules(XmlPullParser parser) throws IOException, XmlPullParserException {
+    private static List<Rule> parseRules(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
         List<Rule> rules = new ArrayList<>();
 
         // Skipping the first event type, which is always {@link XmlPullParser.START_DOCUMENT}
         parser.next();
 
-        // Processing the first tag; which should always be a <RuleList> tag.
+        // Processing the first tag; which should always be a RuleList <RL> tag.
         String nodeName = parser.getName();
-        // Validating that the XML is starting with a <RuleList> tag.
+        // Validating that the XML is starting with a RuleList <RL> tag.
         // Note: This is the only breaking validation to run against XML files in the platform.
         // All rules inside are assumed to be validated at the server. If a rule is found to be
         // corrupt in the XML, it will be skipped to the next rule.
         if (!nodeName.equals(RULE_LIST_TAG)) {
             throw new RuntimeException(
-                    String.format("Rules must start with <RuleList> tag. Found: %s at %s", nodeName,
-                            parser.getPositionDescription()));
+                    String.format("Rules must start with RuleList <RL> tag. Found: %s at %s",
+                            nodeName, parser.getPositionDescription()));
         }
 
         int eventType;
@@ -89,17 +98,150 @@
             if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
                 continue;
             }
-            Rule parsedRule = parseRule(parser);
-            if (parsedRule != null) {
-                rules.add(parsedRule);
-            }
+            rules.add(parseRule(parser));
         }
 
         return rules;
     }
 
-    private Rule parseRule(XmlPullParser parser) {
-        // TODO: Implement rule parser.
-        return null;
+    private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException {
+        Formula formula = null;
+        @Rule.Effect int effect = 0;
+
+        int eventType;
+        while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            String nodeName = parser.getName();
+
+            if (eventType == XmlPullParser.END_TAG && parser.getName().equals(RULE_TAG)) {
+                break;
+            }
+
+            if (eventType == XmlPullParser.START_TAG) {
+                switch (nodeName) {
+                    case OPEN_FORMULA_TAG:
+                        formula = parseOpenFormula(parser);
+                        break;
+                    case ATOMIC_FORMULA_TAG:
+                        formula = parseAtomicFormula(parser);
+                        break;
+                    case EFFECT_TAG:
+                        effect = Integer.parseInt(extractValue(parser));
+                        break;
+                    default:
+                        throw new RuntimeException(
+                                String.format("Found unexpected tag: %s", nodeName));
+                }
+            } else {
+                throw new RuntimeException(
+                        String.format("Found unexpected event type: %d", eventType));
+            }
+        }
+
+        return new Rule(formula, effect);
+    }
+
+    private static Formula parseOpenFormula(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        @OpenFormula.Connector int connector = 0;
+        List<Formula> formulas = new ArrayList<>();
+
+        int eventType;
+        while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            String nodeName = parser.getName();
+
+            if (eventType == XmlPullParser.END_TAG && parser.getName().equals(OPEN_FORMULA_TAG)) {
+                break;
+            }
+
+            if (eventType == XmlPullParser.START_TAG) {
+                switch (nodeName) {
+                    case CONNECTOR_TAG:
+                        connector = Integer.parseInt(extractValue(parser));
+                        break;
+                    case ATOMIC_FORMULA_TAG:
+                        formulas.add(parseAtomicFormula(parser));
+                        break;
+                    case OPEN_FORMULA_TAG:
+                        formulas.add(parseOpenFormula(parser));
+                        break;
+                    default:
+                        throw new RuntimeException(
+                                String.format("Found unexpected tag: %s", nodeName));
+                }
+            } else {
+                throw new RuntimeException(
+                        String.format("Found unexpected event type: %d", eventType));
+            }
+        }
+
+        return new OpenFormula(connector, formulas);
+    }
+
+    private static Formula parseAtomicFormula(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        @AtomicFormula.Key int key = 0;
+        @AtomicFormula.Operator int operator = 0;
+        String value = null;
+
+        int eventType;
+        while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            String nodeName = parser.getName();
+
+            if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ATOMIC_FORMULA_TAG)) {
+                break;
+            }
+
+            if (eventType == XmlPullParser.START_TAG) {
+                switch (nodeName) {
+                    case KEY_TAG:
+                        key = Integer.parseInt(extractValue(parser));
+                        break;
+                    case OPERATOR_TAG:
+                        operator = Integer.parseInt(extractValue(parser));
+                        break;
+                    case VALUE_TAG:
+                        value = extractValue(parser);
+                        break;
+                    default:
+                        throw new RuntimeException(
+                                String.format("Found unexpected tag: %s", nodeName));
+                }
+            } else {
+                throw new RuntimeException(
+                        String.format("Found unexpected event type: %d", eventType));
+            }
+        }
+        return constructAtomicFormulaBasedOnKey(key, operator, value);
+    }
+
+    private static Formula constructAtomicFormulaBasedOnKey(@AtomicFormula.Key int key,
+            @AtomicFormula.Operator int operator, String value) {
+        switch (key) {
+            case AtomicFormula.PACKAGE_NAME:
+            case AtomicFormula.INSTALLER_NAME:
+            case AtomicFormula.APP_CERTIFICATE:
+            case AtomicFormula.INSTALLER_CERTIFICATE:
+                return new AtomicFormula.StringAtomicFormula(key, value);
+            case AtomicFormula.PRE_INSTALLED:
+                return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value));
+            case AtomicFormula.VERSION_CODE:
+                return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value));
+            default:
+                throw new RuntimeException(String.format("Found unexpected key: %d", key));
+        }
+    }
+
+    private static String extractValue(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        String value;
+        int eventType = parser.next();
+        if (eventType == XmlPullParser.TEXT) {
+            value = parser.getText();
+            eventType = parser.next();
+            if (eventType == XmlPullParser.END_TAG) {
+                return value;
+            }
+        }
+        throw new RuntimeException(String.format("Found unexpected event type: %d", eventType));
     }
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index ecb00a4..ee95d2b 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -19,17 +19,18 @@
 import com.android.server.integrity.model.Rule;
 
 import java.io.OutputStream;
+import java.util.List;
 
 /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
 public class RuleBinarySerializer implements RuleSerializer {
 
     @Override
-    public void serialize(Rule rule, OutputStream outputStream) {
+    public void serialize(List<Rule> rules, OutputStream outputStream) {
         // TODO: Implement stream serializer.
     }
 
     @Override
-    public String serialize(Rule rule) {
+    public String serialize(List<Rule> rules) {
         // TODO: Implement text serializer.
         return null;
     }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
new file mode 100644
index 0000000..60cfc48
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.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.server.integrity.serializer;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when rule serialization fails.
+ */
+public class RuleSerializeException extends Exception {
+    public RuleSerializeException(@NonNull String message) {
+        super(message);
+    }
+
+    public RuleSerializeException(@NonNull String message, @NonNull Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
index 07a912f..5c99c5a 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -19,13 +19,14 @@
 import com.android.server.integrity.model.Rule;
 
 import java.io.OutputStream;
+import java.util.List;
 
 /** A helper class to serialize rules from the {@link Rule} model. */
 public interface RuleSerializer {
 
-    /** Serialize a rule to an output stream */
-    void serialize(Rule rule, OutputStream outputStream);
+    /** Serialize rules to an output stream */
+    void serialize(List<Rule> rules, OutputStream outputStream) throws RuleSerializeException;
 
-    /** Serialize a rule to a string. */
-    String serialize(Rule rule);
+    /** Serialize rules to a string. */
+    String serialize(List<Rule> rule) throws RuleSerializeException;
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index 62973e2..b0805fc 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -16,21 +16,142 @@
 
 package com.android.server.integrity.serializer;
 
+import android.util.Xml;
+
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
 import com.android.server.integrity.model.Rule;
 
-import java.io.OutputStream;
+import org.xmlpull.v1.XmlSerializer;
 
-/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * A helper class to serialize rules from the {@link Rule} model to Xml representation.
+ */
 public class RuleXmlSerializer implements RuleSerializer {
 
+    public static final String TAG = "RuleXmlSerializer";
+    private static final String NAMESPACE = "";
+
+    private static final String RULE_LIST_TAG = "RL";
+    private static final String RULE_TAG = "R";
+    private static final String OPEN_FORMULA_TAG = "OF";
+    private static final String ATOMIC_FORMULA_TAG = "AF";
+    private static final String EFFECT_TAG = "E";
+    private static final String KEY_TAG = "K";
+    private static final String OPERATOR_TAG = "O";
+    private static final String VALUE_TAG = "V";
+    private static final String CONNECTOR_TAG = "C";
+
     @Override
-    public void serialize(Rule rule, OutputStream outputStream) {
-        // TODO: Implement stream serializer.
+    public void serialize(List<Rule> rules, OutputStream outputStream)
+            throws RuleSerializeException {
+        try {
+            XmlSerializer xmlSerializer = Xml.newSerializer();
+            xmlSerializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
+            serializeRules(rules, xmlSerializer);
+        } catch (Exception e) {
+            throw new RuleSerializeException(e.getMessage(), e);
+        }
     }
 
     @Override
-    public String serialize(Rule rule) {
-        // TODO: Implement text serializer.
-        return null;
+    public String serialize(List<Rule> rules) throws RuleSerializeException {
+        try {
+            XmlSerializer xmlSerializer = Xml.newSerializer();
+            StringWriter writer = new StringWriter();
+            xmlSerializer.setOutput(writer);
+            serializeRules(rules, xmlSerializer);
+            return writer.toString();
+        } catch (Exception e) {
+            throw new RuleSerializeException(e.getMessage(), e);
+        }
+    }
+
+    private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException {
+        xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);
+        for (Rule rule : rules) {
+            serialize(rule, xmlSerializer);
+        }
+        xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
+        xmlSerializer.endDocument();
+    }
+
+    private void serialize(Rule rule, XmlSerializer xmlSerializer) throws IOException {
+        if (rule == null) {
+            return;
+        }
+        xmlSerializer.startTag(NAMESPACE, RULE_TAG);
+        serializeFormula(rule.getFormula(), xmlSerializer);
+        serializeValue(EFFECT_TAG, String.valueOf(rule.getEffect()), xmlSerializer);
+        xmlSerializer.endTag(NAMESPACE, RULE_TAG);
+    }
+
+    private void serializeFormula(Formula formula, XmlSerializer xmlSerializer) throws IOException {
+        if (formula instanceof AtomicFormula) {
+            serializeAtomicFormula((AtomicFormula) formula, xmlSerializer);
+        } else if (formula instanceof OpenFormula) {
+            serializeOpenFormula((OpenFormula) formula, xmlSerializer);
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("Invalid formula type: %s", formula.getClass()));
+        }
+    }
+
+    private void serializeOpenFormula(OpenFormula openFormula, XmlSerializer xmlSerializer)
+            throws IOException {
+        if (openFormula == null) {
+            return;
+        }
+        xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG);
+        serializeValue(CONNECTOR_TAG, String.valueOf(openFormula.getConnector()), xmlSerializer);
+        for (Formula formula : openFormula.getFormulas()) {
+            serializeFormula(formula, xmlSerializer);
+        }
+        xmlSerializer.endTag(NAMESPACE, OPEN_FORMULA_TAG);
+    }
+
+    private void serializeAtomicFormula(AtomicFormula atomicFormula, XmlSerializer xmlSerializer)
+            throws IOException {
+        if (atomicFormula == null) {
+            return;
+        }
+        xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG);
+        serializeValue(KEY_TAG, String.valueOf(atomicFormula.getKey()), xmlSerializer);
+        if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) {
+            serializeValue(VALUE_TAG,
+                    ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer);
+        } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) {
+            serializeValue(OPERATOR_TAG,
+                    String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()),
+                    xmlSerializer);
+            serializeValue(VALUE_TAG,
+                    String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()),
+                    xmlSerializer);
+        } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) {
+            serializeValue(VALUE_TAG,
+                    String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()),
+                    xmlSerializer);
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("Invalid atomic formula type: %s", atomicFormula.getClass()));
+        }
+        xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG);
+    }
+
+    private void serializeValue(String tag, String value, XmlSerializer xmlSerializer)
+            throws IOException {
+        if (value == null) {
+            return;
+        }
+        xmlSerializer.startTag(NAMESPACE, tag);
+        xmlSerializer.text(value);
+        xmlSerializer.endTag(NAMESPACE, tag);
     }
 }
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 53d922b..f23ac34 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -721,6 +721,10 @@
             }
             return VerifyCredentialResponse.fromGateKeeperResponse(response);
         } else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
+            if (!isWeaverAvailable()) {
+                Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
+                return VerifyCredentialResponse.ERROR;
+            }
             PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
             byte[] pwdToken = computePasswordToken(userCredential, pwd);
             int weaverSlot = persistentData.userId;
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 626bf1c..51a0df3 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -84,9 +84,9 @@
         mCallback = callback;
     }
 
-    public void selectRoute(String packageName, String routeId) {
+    public void requestSelectRoute(String packageName, String routeId, int seq) {
         if (mConnectionReady) {
-            mActiveConnection.selectRoute(packageName, routeId);
+            mActiveConnection.requestSelectRoute(packageName, routeId, seq);
             updateBinding();
         }
     }
@@ -328,9 +328,9 @@
             mClient.dispose();
         }
 
-        public void selectRoute(String packageName, String routeId) {
+        public void requestSelectRoute(String packageName, String routeId, int seq) {
             try {
-                mProvider.selectRoute(packageName, routeId);
+                mProvider.requestSelectRoute(packageName, routeId, seq);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
             }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2e97f6a..adfb9cb 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -29,10 +29,13 @@
 import android.media.IMediaRouterClient;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRouter2;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -60,6 +63,7 @@
 class MediaRouter2ServiceImpl {
     private static final String TAG = "MR2ServiceImpl";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final long ROUTE_SELECTION_REQUEST_TIMEOUT_MS = 5000L;
 
     private final Context mContext;
     private final Object mLock = new Object();
@@ -72,6 +76,8 @@
     private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private int mCurrentUserId = -1;
+    @GuardedBy("mLock")
+    private int mSelectRouteRequestSequenceNumber = 0;
 
     MediaRouter2ServiceImpl(Context context) {
         mContext = context;
@@ -189,12 +195,12 @@
         }
     }
 
-    public void selectRoute2(@NonNull IMediaRouter2Client client,
+    public void requestSelectRoute2(@NonNull IMediaRouter2Client client,
             @Nullable MediaRoute2Info route) {
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                selectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+                requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -375,24 +381,38 @@
         }
     }
 
-    private void selectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+    private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
         if (clientRecord != null) {
             MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
-            clientRecord.mSelectedRoute = route;
+            clientRecord.mSelectingRoute = route;
 
             UserHandler handler = clientRecord.mUserRecord.mHandler;
             //TODO: Handle transfer instead of unselect and select
             if (oldRoute != null) {
-                handler.sendMessage(
-                        obtainMessage(UserHandler::unselectRoute, handler, clientRecord,
-                                oldRoute));
+                handler.sendMessage(obtainMessage(
+                        UserHandler::unselectRoute, handler, clientRecord.mPackageName, oldRoute));
             }
             if (route != null) {
-                handler.sendMessage(
-                        obtainMessage(UserHandler::selectRoute, handler, clientRecord, route));
+                final int seq = mSelectRouteRequestSequenceNumber;
+                mSelectRouteRequestSequenceNumber++;
+
+                handler.sendMessage(obtainMessage(
+                        UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
+                        route, seq));
+
+                // Remove all previous timeout messages
+                for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
+                    clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
+                }
+                clientRecord.mSelectRouteSequenceNumbers.clear();
+
+                // When the request is not handled in timeout, set the client's route to default.
+                Message timeoutMsg = obtainMessage(UserHandler::handleRouteSelectionTimeout,
+                        handler, clientRecord.mPackageName, route);
+                timeoutMsg.what = seq; // Make the message cancelable.
+                handler.sendMessageDelayed(timeoutMsg, ROUTE_SELECTION_REQUEST_TIMEOUT_MS);
+                clientRecord.mSelectRouteSequenceNumbers.add(seq);
             }
-            handler.sendMessage(
-                    obtainMessage(UserHandler::updateClientUsage, handler, clientRecord));
         }
     }
 
@@ -473,6 +493,11 @@
                             userRecord.mHandler, manager));
 
             for (ClientRecord clientRecord : userRecord.mClientRecords) {
+                // TODO: Do not use updateClientUsage since it updates all managers.
+                // Instead, Notify only to the manager that is currently being registered.
+
+                // TODO: UserRecord <-> ClientRecord, why do they reference each other?
+                // How about removing mUserRecord from clientRecord?
                 clientRecord.mUserRecord.mHandler.sendMessage(
                         obtainMessage(UserHandler::updateClientUsage,
                             clientRecord.mUserRecord.mHandler, clientRecord));
@@ -494,12 +519,13 @@
             String packageName, MediaRoute2Info route) {
         ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
         if (managerRecord != null) {
-            ClientRecord clientRecord = managerRecord.mUserRecord.findClientRecord(packageName);
+            ClientRecord clientRecord =
+                    managerRecord.mUserRecord.findClientRecordLocked(packageName);
             if (clientRecord == null) {
                 Slog.w(TAG, "Ignoring route selection for unknown client.");
             }
             if (clientRecord != null && managerRecord.mTrusted) {
-                selectRoute2Locked(clientRecord, route);
+                requestSelectRoute2Locked(clientRecord, route);
             }
         }
     }
@@ -598,7 +624,7 @@
             mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
         }
 
-        ClientRecord findClientRecord(String packageName) {
+        ClientRecord findClientRecordLocked(String packageName) {
             for (ClientRecord clientRecord : mClientRecords) {
                 if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
                     return clientRecord;
@@ -611,12 +637,15 @@
     class ClientRecord {
         public final UserRecord mUserRecord;
         public final String mPackageName;
+        public final List<Integer> mSelectRouteSequenceNumbers;
         public List<String> mControlCategories;
+        public MediaRoute2Info mSelectingRoute;
         public MediaRoute2Info mSelectedRoute;
 
         ClientRecord(UserRecord userRecord, String packageName) {
             mUserRecord = userRecord;
             mPackageName = packageName;
+            mSelectRouteSequenceNumbers = new ArrayList<>();
             mControlCategories = Collections.emptyList();
         }
     }
@@ -752,6 +781,15 @@
             sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
         }
 
+        // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
+        // Make this method to be called.
+        public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+                String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
+            sendMessage(PooledLambda.obtainMessage(
+                    UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
+                    controlHints, seq));
+        }
+
         private void updateProvider(MediaRoute2ProviderProxy provider) {
             int providerIndex = getProviderInfoIndex(provider.getUniqueId());
             MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
@@ -834,24 +872,104 @@
             return -1;
         }
 
-        private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+        private void updateSelectedRoute(MediaRoute2ProviderProxy provider,
+                String clientPackageName, MediaRoute2Info selectedRoute, Bundle controlHints,
+                int seq) {
+            if (selectedRoute == null
+                    || !TextUtils.equals(clientPackageName, selectedRoute.getClientPackageName())) {
+                Log.w(TAG, "Ignoring route selection which has non-matching clientPackageName.");
+                return;
+            }
+
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+
+            ClientRecord clientRecord;
+            synchronized (service.mLock) {
+                clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
+            }
+            if (!(clientRecord instanceof Client2Record)) {
+                Log.w(TAG, "Ignoring route selection for unknown client.");
+                unselectRoute(clientPackageName, selectedRoute);
+                return;
+            }
+
+            if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
+                    clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
+                Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
+                        + clientRecord.mSelectingRoute + " route=" + selectedRoute);
+                unselectRoute(clientPackageName, selectedRoute);
+                return;
+            }
+            clientRecord.mSelectingRoute = null;
+            clientRecord.mSelectedRoute = selectedRoute;
+
+            notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+                    selectedRoute,
+                    MediaRouter2.SELECT_REASON_USER_SELECTED,
+                    controlHints);
+            updateClientUsage(clientRecord);
+
+            // Remove the fallback route selection message.
+            removeMessages(seq);
+        }
+
+        private void handleRouteSelectionTimeout(String clientPackageName,
+                MediaRoute2Info selectingRoute) {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+
+            ClientRecord clientRecord;
+            synchronized (service.mLock) {
+                clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
+            }
+            if (!(clientRecord instanceof Client2Record)) {
+                Log.w(TAG, "Ignoring fallback route selection for unknown client.");
+                return;
+            }
+
+            if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
+                    clientRecord.mSelectingRoute.getUniqueId(), selectingRoute.getUniqueId())) {
+                Log.w(TAG, "Ignoring invalid selectFallbackRoute call. "
+                        + "Current selectingRoute=" + clientRecord.mSelectingRoute
+                        + " , original selectingRoute=" + selectingRoute);
+                return;
+            }
+
+            clientRecord.mSelectingRoute = null;
+            // TODO: When the default route is introduced, make mSelectedRoute always non-null.
+            MediaRoute2Info fallbackRoute = null;
+            clientRecord.mSelectedRoute = fallbackRoute;
+
+            notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+                    fallbackRoute,
+                    MediaRouter2.SELECT_REASON_FALLBACK,
+                    Bundle.EMPTY /* controlHints */);
+            updateClientUsage(clientRecord);
+        }
+
+        private void requestSelectRoute(String clientPackageName, MediaRoute2Info route, int seq) {
             if (route != null) {
                 MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
                 if (provider == null) {
                     Slog.w(TAG, "Ignoring to select route of unknown provider " + route);
                 } else {
-                    provider.selectRoute(clientRecord.mPackageName, route.getId());
+                    provider.requestSelectRoute(clientPackageName, route.getId(), seq);
                 }
             }
         }
 
-        private void unselectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+        private void unselectRoute(String clientPackageName, MediaRoute2Info route) {
             if (route != null) {
                 MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
                 if (provider == null) {
                     Slog.w(TAG, "Ignoring to unselect route of unknown provider " + route);
                 } else {
-                    provider.unselectRoute(clientRecord.mPackageName, route.getId());
+                    provider.unselectRoute(clientPackageName, route.getId());
                 }
             }
         }
@@ -922,6 +1040,15 @@
             }
         }
 
+        private void notifyRouteSelectedToClient(IMediaRouter2Client client,
+                MediaRoute2Info route, int reason, Bundle controlHints) {
+            try {
+                client.notifyRouteSelected(route, reason, controlHints);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify routes selected. Client probably died.", ex);
+            }
+        }
+
         private void notifyRoutesAddedToClients(List<IMediaRouter2Client> clients,
                 List<MediaRoute2Info> routes) {
             for (IMediaRouter2Client client : clients) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index afd92f6..ecc1aba 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -459,8 +459,8 @@
 
     // Binder call
     @Override
-    public void selectRoute2(IMediaRouter2Client client, MediaRoute2Info route) {
-        mService2.selectRoute2(client, route);
+    public void requestSelectRoute2(IMediaRouter2Client client, MediaRoute2Info route) {
+        mService2.requestSelectRoute2(client, route);
     }
 
     // Binder call
diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java
index 990eba1..0541797 100644
--- a/services/core/java/com/android/server/pm/InstallSource.java
+++ b/services/core/java/com/android/server/pm/InstallSource.java
@@ -18,8 +18,6 @@
 
 import android.annotation.Nullable;
 
-import com.android.internal.util.IndentingPrintWriter;
-
 import java.util.Objects;
 
 /**
@@ -31,13 +29,25 @@
      * An instance of InstallSource representing an absence of knowledge of the source of
      * a package. Used in preference to null.
      */
-    static final InstallSource EMPTY = new InstallSource(null, null, false);
+    static final InstallSource EMPTY = new InstallSource(null, null, null, false);
+
+    /** We also memoize this case because it is common - all un-updated system apps. */
+    private static final InstallSource EMPTY_ORPHANED = new InstallSource(null, null, null, true);
 
     /** The package that requested the installation, if known. */
     @Nullable
     final String initiatingPackageName;
 
     /**
+     * The package on behalf of which the initiating package requested the installation, if any.
+     * For example if a downloaded APK is installed via the Package Installer this could be the
+     * app that performed the download. This value is provided by the initiating package and not
+     * verified by the framework.
+     */
+    @Nullable
+    final String originatingPackageName;
+
+    /**
      * Package name of the app that installed this package (the installer of record). Note that
      * this may be modified.
      */
@@ -48,47 +58,55 @@
     final boolean isOrphaned;
 
     static InstallSource create(@Nullable String initiatingPackageName,
-            @Nullable String installerPackageName) {
-        return create(initiatingPackageName, installerPackageName, false);
-    }
-
-    static InstallSource create(@Nullable String initiatingPackageName,
-            @Nullable String installerPackageName, boolean isOrphaned) {
-        if (initiatingPackageName == null && installerPackageName == null && !isOrphaned) {
-            return EMPTY;
-        }
-        return new InstallSource(
-                initiatingPackageName == null ? null : initiatingPackageName.intern(),
-                installerPackageName == null ? null : installerPackageName.intern(),
+            @Nullable String originatingPackageName, @Nullable String installerPackageName,
+            boolean isOrphaned) {
+        return createInternal(
+                intern(initiatingPackageName),
+                intern(originatingPackageName),
+                intern(installerPackageName),
                 isOrphaned);
     }
 
-    private InstallSource(@Nullable String initiatingPackageName,
-            @Nullable String installerPackageName, boolean isOrphaned) {
-        this.initiatingPackageName = initiatingPackageName;
-        this.isOrphaned = isOrphaned;
-        this.installerPackageName = installerPackageName;
+    private static InstallSource createInternal(@Nullable String initiatingPackageName,
+            @Nullable String originatingPackageName, @Nullable String installerPackageName,
+            boolean isOrphaned) {
+        if (initiatingPackageName == null && originatingPackageName == null
+                && installerPackageName == null) {
+            return isOrphaned ? EMPTY_ORPHANED : EMPTY;
+        }
+        return new InstallSource(initiatingPackageName, originatingPackageName,
+                installerPackageName, isOrphaned);
     }
 
-    void dump(IndentingPrintWriter pw) {
-        pw.printPair("installerPackageName", installerPackageName);
-        pw.printPair("installInitiatingPackageName", initiatingPackageName);
+    private InstallSource(@Nullable String initiatingPackageName,
+            @Nullable String originatingPackageName, @Nullable String installerPackageName,
+            boolean isOrphaned) {
+        this.initiatingPackageName = initiatingPackageName;
+        this.originatingPackageName = originatingPackageName;
+        this.installerPackageName = installerPackageName;
+        this.isOrphaned = isOrphaned;
     }
 
     /**
      * Return an InstallSource the same as this one except with the specified installerPackageName.
      */
     InstallSource setInstallerPackage(String installerPackageName) {
-        return Objects.equals(installerPackageName, this.installerPackageName) ? this
-                : create(initiatingPackageName, installerPackageName, isOrphaned);
+        if (Objects.equals(installerPackageName, this.installerPackageName)) {
+            return this;
+        }
+        return createInternal(initiatingPackageName, originatingPackageName,
+                intern(installerPackageName), isOrphaned);
     }
 
     /**
      * Return an InstallSource the same as this one except with the specified value for isOrphaned.
      */
     InstallSource setIsOrphaned(boolean isOrphaned) {
-        return isOrphaned == this.isOrphaned ? this
-                : create(initiatingPackageName, installerPackageName, isOrphaned);
+        if (isOrphaned == this.isOrphaned) {
+            return this;
+        }
+        return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
+                isOrphaned);
     }
 
     /**
@@ -102,6 +120,7 @@
 
         boolean modified = false;
         String initiatingPackageName = this.initiatingPackageName;
+        String originatingPackageName = this.originatingPackageName;
         String installerPackageName = this.installerPackageName;
         boolean isOrphaned = this.isOrphaned;
 
@@ -109,14 +128,25 @@
             initiatingPackageName = null;
             modified = true;
         }
+        if (packageName.equals(originatingPackageName)) {
+            originatingPackageName = null;
+            modified = true;
+        }
         if (packageName.equals(installerPackageName)) {
             installerPackageName = null;
             isOrphaned = true;
             modified = true;
         }
 
-        return modified
-                ? create(initiatingPackageName, installerPackageName, isOrphaned)
-                : this;
+        if (!modified) {
+            return this;
+        }
+        return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
+                isOrphaned);
+    }
+
+    @Nullable
+    private static String intern(@Nullable String packageName) {
+        return packageName == null ? null : packageName.intern();
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed2bb3d5..6564e71 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -512,6 +512,16 @@
             }
         }
 
+        String originatingPackageName = null;
+        if (params.originatingUid != SessionParams.UID_UNKNOWN
+                && params.originatingUid != callingUid) {
+            String[] packages = mPm.getPackagesForUid(params.originatingUid);
+            if (packages != null && packages.length > 0) {
+                // Choose an arbitrary representative package in the case of a shared UID.
+                originatingPackageName = packages[0];
+            }
+        }
+
         if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) {
             params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
         } else {
@@ -624,7 +634,7 @@
             }
         }
         InstallSource installSource = InstallSource.create(installerPackageName,
-                requestedInstallerPackageName);
+                originatingPackageName, requestedInstallerPackageName, false);
         session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                 mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
                 installSource, params, createdMillis,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index feb1271..631df0ff 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -148,6 +148,8 @@
     private static final String ATTR_INSTALLER_UID = "installerUid";
     private static final String ATTR_INITIATING_PACKAGE_NAME =
             "installInitiatingPackageName";
+    private static final String ATTR_ORIGINATING_PACKAGE_NAME =
+            "installOriginatingPackageName";
     private static final String ATTR_CREATED_MILLIS = "createdMillis";
     private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
     private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
@@ -1227,7 +1229,7 @@
             }
 
             mInstallerUid = newOwnerAppInfo.uid;
-            mInstallSource = InstallSource.create(packageName, packageName);
+            mInstallSource = InstallSource.create(packageName, null, packageName, false);
         }
 
         // Persist the fact that we've sealed ourselves to prevent
@@ -2336,7 +2338,9 @@
 
         pw.printPair("userId", userId);
         pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
-        mInstallSource.dump(pw);
+        pw.printPair("installerPackageName", mInstallSource.installerPackageName);
+        pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
+        pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
         pw.printPair("mInstallerUid", mInstallerUid);
         pw.printPair("createdMillis", createdMillis);
         pw.printPair("updatedMillis", updatedMillis);
@@ -2420,6 +2424,8 @@
             writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
             writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
                     mInstallSource.initiatingPackageName);
+            writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
+                    mInstallSource.originatingPackageName);
             writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
             writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
             if (stageDir != null) {
@@ -2527,6 +2533,8 @@
                 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
         final String installInitiatingPackageName =
                 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
+        final String installOriginatingPackageName =
+                readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
         final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
         long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
         final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
@@ -2619,7 +2627,7 @@
         }
 
         InstallSource installSource = InstallSource.create(installInitiatingPackageName,
-                installerPackageName);
+                installOriginatingPackageName, installerPackageName, false);
         return new PackageInstallerSession(callback, context, pm, sessionProvider,
                 installerThread, stagingManager, sessionId, userId, installerUid,
                 installSource, params, createdMillis, stageDir, stageCid,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f1c84b8..525d357 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -115,6 +115,7 @@
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.LinkedList;
@@ -438,8 +439,14 @@
         }
     }
 
-    private void setParamsSize(InstallParams params, String inPath) {
-        if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
+    private void setParamsSize(InstallParams params, List<String> inPaths) {
+        if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) {
+            return;
+        }
+
+        long sessionSize = 0;
+
+        for (String inPath : inPaths) {
             final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
             if (fd == null) {
                 getErrPrintWriter().println("Error: Can't open file: " + inPath);
@@ -449,8 +456,8 @@
                 ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0);
                 PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                         null, null);
-                params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
-                        pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor()));
+                sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
+                        params.sessionParams.abiOverride, fd.getFileDescriptor());
             } catch (PackageParserException | IOException e) {
                 getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
                 throw new IllegalArgumentException(
@@ -462,6 +469,7 @@
                 }
             }
         }
+        params.sessionParams.setSize(sessionSize);
     }
     /**
      * Displays the package file for a package.
@@ -1148,23 +1156,44 @@
     private int runInstall() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final InstallParams params = makeInstallParams();
-        final String inPath = getNextArg();
 
-        setParamsSize(params, inPath);
+        ArrayList<String> inPaths = getRemainingArgs();
+        if (inPaths.isEmpty()) {
+            inPaths.add(STDIN_PATH);
+        }
+
+        final boolean hasSplits = inPaths.size() > 1;
+
+        if (STDIN_PATH.equals(inPaths.get(0))) {
+            if (hasSplits) {
+                pw.println("Error: can't specify SPLIT(s) along with STDIN");
+                return 1;
+            }
+            if (params.sessionParams.sizeBytes == -1) {
+                pw.println("Error: must either specify a package size or an APK file");
+                return 1;
+            }
+        }
+
+        final boolean isApex =
+                (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+        if (isApex && hasSplits) {
+            pw.println("Error: can't specify SPLIT(s) for APEX");
+            return 1;
+        }
+
+        setParamsSize(params, inPaths);
         final int sessionId = doCreateSession(params.sessionParams,
                 params.installerPackageName, params.userId);
         boolean abandonSession = true;
         try {
-            if (inPath == null && params.sessionParams.sizeBytes == -1) {
-                pw.println("Error: must either specify a package size or an APK file");
-                return 1;
-            }
-            final boolean isApex =
-                    (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
-            String splitName = "base." + (isApex ? "apex" : "apk");
-            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
-                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
+            for (String inPath : inPaths) {
+                String splitName = hasSplits ? (new File(inPath)).getName()
+                        : "base." + (isApex ? "apex" : "apk");
+                if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
+                        false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+                    return 1;
+                }
             }
             if (doCommitSession(sessionId, false /*logSuccess*/)
                     != PackageInstaller.STATUS_SUCCESS) {
@@ -1283,12 +1312,12 @@
 
         final int sessionId = Integer.parseInt(getNextArg());
 
-        final String splitName = getNextArg();
-        if (splitName == null) {
+        ArrayList<String> splitNames = getRemainingArgs();
+        if (splitNames.isEmpty()) {
             pw.println("Error: split name not specified");
             return 1;
         }
-        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
+        return doRemoveSplits(sessionId, splitNames, true /*logSuccess*/);
     }
 
     private int runInstallExisting() throws RemoteException {
@@ -1731,6 +1760,15 @@
         return 0;
     }
 
+    private ArrayList<String> getRemainingArgs() {
+        ArrayList<String> args = new ArrayList<>();
+        String arg;
+        while ((arg = getNextArg()) != null) {
+            args.add(arg);
+        }
+        return args;
+    }
+
     private static class SnapshotRuntimeProfileCallback
             extends ISnapshotRuntimeProfileCallback.Stub {
         private boolean mSuccess = false;
@@ -1802,9 +1840,9 @@
         }
 
         // if a split is specified, just remove it and not the whole package
-        final String splitName = getNextArg();
-        if (splitName != null) {
-            return runRemoveSplit(packageName, splitName);
+        ArrayList<String> splitNames = getRemainingArgs();
+        if (!splitNames.isEmpty()) {
+            return runRemoveSplits(packageName, splitNames);
         }
 
         userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
@@ -1852,7 +1890,8 @@
         }
     }
 
-    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
+    private int runRemoveSplits(String packageName, Collection<String> splitNames)
+            throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
         sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
@@ -1861,7 +1900,7 @@
                 doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
         boolean abandonSession = true;
         try {
-            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
+            if (doRemoveSplits(sessionId, splitNames, false /*logSuccess*/)
                     != PackageInstaller.STATUS_SUCCESS) {
                 return 1;
             }
@@ -2945,14 +2984,17 @@
         }
     }
 
-    private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
+    private int doRemoveSplits(int sessionId, Collection<String> splitNames, boolean logSuccess)
             throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
-            session.removeSplit(splitName);
+
+            for (String splitName : splitNames) {
+                session.removeSplit(splitName);
+            }
 
             if (logSuccess) {
                 pw.println("Success");
@@ -3237,9 +3279,9 @@
         pw.println("       [--enable-rollback]");
         pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
         pw.println("       [--apex] [--wait TIMEOUT]");
-        pw.println("       [PATH|-]");
-        pw.println("    Install an application.  Must provide the apk data to install, either as a");
-        pw.println("    file path or '-' to read from stdin.  Options are:");
+        pw.println("       [PATH [SPLIT...]|-]");
+        pw.println("    Install an application.  Must provide the apk data to install, either as");
+        pw.println("    file path(s) or '-' to read from stdin.  Options are:");
         pw.println("      -R: disallow replacement of existing application");
         pw.println("      -t: allow test packages");
         pw.println("      -i: specify package name of installer owning the app");
@@ -3293,6 +3335,9 @@
         pw.println("    will be read from stdin.  Options are:");
         pw.println("      -S: size in bytes of package, required for stdin");
         pw.println("");
+        pw.println("  install-remove SESSION_ID SPLIT...");
+        pw.println("    Mark SPLIT(s) as removed in the given install session.");
+        pw.println("");
         pw.println("  install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
         pw.println("    Add one or more session IDs to a multi-package session.");
         pw.println("");
@@ -3317,9 +3362,10 @@
         pw.println("");
         pw.println("  move-primary-storage [internal|UUID]");
         pw.println("");
-        pw.println("  pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE [SPLIT]");
+        pw.println("  uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE]");
+        pw.println("       PACKAGE [SPLIT...]");
         pw.println("    Remove the given package name from the system.  May remove an entire app");
-        pw.println("    if no SPLIT name is specified, otherwise will remove only the split of the");
+        pw.println("    if no SPLIT names specified, otherwise will remove only the splits of the");
         pw.println("    given app.  Options are:");
         pw.println("      -k: keep the data and cache directories around after package removal.");
         pw.println("      --user: remove the app from the given user.");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 4fca91a..1254891 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -209,6 +209,8 @@
             long sourceToken = proto.start(PackageProto.INSTALL_SOURCE);
             proto.write(PackageProto.InstallSourceProto.INITIATING_PACKAGE_NAME,
                     installSource.initiatingPackageName);
+            proto.write(PackageProto.InstallSourceProto.ORIGINATING_PACKAGE_NAME,
+                    installSource.originatingPackageName);
             proto.end(sourceToken);
         }
         writeUsersInfoToProto(proto, PackageProto.USERS);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 66c77f5..5f3650c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2848,6 +2848,9 @@
         if (installSource.initiatingPackageName != null) {
             serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
         }
+        if (installSource.originatingPackageName != null) {
+            serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
+        }
         if (pkg.volumeUuid != null) {
             serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
         }
@@ -3605,6 +3608,7 @@
         String systemStr = null;
         String installerPackageName = null;
         String isOrphaned = null;
+        String installOriginatingPackageName = null;
         String installInitiatingPackageName = null;
         String volumeUuid = null;
         String categoryHintString = null;
@@ -3653,6 +3657,7 @@
             installerPackageName = parser.getAttributeValue(null, "installer");
             isOrphaned = parser.getAttributeValue(null, "isOrphaned");
             installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
+            installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
             volumeUuid = parser.getAttributeValue(null, "volumeUuid");
             categoryHintString = parser.getAttributeValue(null, "categoryHint");
             if (categoryHintString != null) {
@@ -3808,7 +3813,8 @@
         if (packageSetting != null) {
             packageSetting.uidError = "true".equals(uidError);
             packageSetting.installSource = InstallSource.create(
-                    installInitiatingPackageName, installerPackageName, "true".equals(isOrphaned));
+                    installInitiatingPackageName, installOriginatingPackageName,
+                    installerPackageName, "true".equals(isOrphaned));
             packageSetting.volumeUuid = volumeUuid;
             packageSetting.categoryHint = categoryHint;
             packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index b3f1867..cc5aec2 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -314,9 +314,13 @@
             case ArtManager.PROFILE_APPS :
                 return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
             case ArtManager.PROFILE_BOOT_IMAGE:
+                // The device config property overrides the system property version.
+                boolean profileBootClassPath = SystemProperties.getBoolean(
+                        "persist.device_config.runtime_native_boot.profilebootclasspath",
+                        SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false));
                 return (Build.IS_USERDEBUG || Build.IS_ENG) &&
                         SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
-                        SystemProperties.getBoolean("dalvik.vm.profilebootimage", false);
+                        profileBootClassPath;
             default:
                 throw new IllegalArgumentException("Invalid profile type:" + profileType);
         }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 01250db..1f37faf 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -213,15 +213,6 @@
         public Rect getDisplayFrameLw();
 
         /**
-         * Retrieve the frame of the area inside the overscan region of the
-         * display that this window was last laid out in.  Must be called with the
-         * window manager lock held.
-         *
-         * @return Rect The rectangle holding the display overscan frame.
-         */
-        public Rect getOverscanFrameLw();
-
-        /**
          * Retrieve the frame of the content area that this window was last
          * laid out in.  This is the area in which the content of the window
          * should be placed.  It will be smaller than the display frame to
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f78d263..add0b01 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,8 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.security.keystore.IKeystoreService;
 import android.util.Slog;
 
 import com.android.internal.policy.IKeyguardService;
@@ -53,16 +51,11 @@
     private final LockPatternUtils mLockPatternUtils;
     private final StateCallback mCallback;
 
-    IKeystoreService mKeystoreService;
-
     public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
         mCallback = callback;
 
-        mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
-                .getService("android.security.keystore"));
-
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -95,23 +88,6 @@
         mIsShowing = showing;
 
         mCallback.onShowingChanged();
-        int retry = 2;
-        while (retry > 0) {
-            try {
-                mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
-                break;
-            } catch (RemoteException e) {
-                if (retry == 2) {
-                    Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
-                            + " -> refreshing service token and retrying");
-                    mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
-                            .getService("android.security.keystore"));
-                } else {
-                    Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
-                }
-                --retry;
-            }
-        }
     }
 
     @Override // Binder interface
@@ -123,10 +99,6 @@
         mCurrentUserId = userId;
     }
 
-    private synchronized int getCurrentUser() {
-        return mCurrentUserId;
-    }
-
     @Override // Binder interface
     public void onInputRestrictedStateChanged(boolean inputRestricted) {
         mInputRestricted = inputRestricted;
diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
index 8431ae4..c1eacce 100644
--- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
@@ -15,28 +15,22 @@
  */
 package com.android.server.stats;
 
+import static android.os.Process.PROC_OUT_STRING;
+
 import android.annotation.Nullable;
-import android.os.FileUtils;
-import android.util.Slog;
+import android.os.Process;
 
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.function.BiConsumer;
 
 final class ProcfsMemoryUtil {
-    private static final String TAG = "ProcfsMemoryUtil";
-
-    private static final Pattern STATUS_MEMORY_STATS =
-            Pattern.compile(String.join(
-                    ".*",
-                    "Uid:\\s*(\\d+)\\s*",
-                    "VmHWM:\\s*(\\d+)\\s*kB",
-                    "VmRSS:\\s*(\\d+)\\s*kB",
-                    "RssAnon:\\s*(\\d+)\\s*kB",
-                    "VmSwap:\\s*(\\d+)\\s*kB"), Pattern.DOTALL);
+    private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING };
+    private static final String[] STATUS_KEYS = new String[] {
+            "Uid:",
+            "VmHWM:",
+            "VmRSS:",
+            "RssAnon:",
+            "VmSwap:"
+    };
 
     private ProcfsMemoryUtil() {}
 
@@ -46,30 +40,21 @@
      */
     @Nullable
     static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
-        return parseMemorySnapshotFromStatus(readFile("/proc/" + pid + "/status"));
-    }
-
-    @VisibleForTesting
-    @Nullable
-    static MemorySnapshot parseMemorySnapshotFromStatus(String contents) {
-        if (contents.isEmpty()) {
+        long[] output = new long[STATUS_KEYS.length];
+        output[0] = -1;
+        Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output);
+        if (output[0] == -1 || (output[3] == 0 && output[4] == 0)) {
+            // Could not open file or anon rss / swap are 0 indicating the process is in a zombie
+            // state.
             return null;
         }
-        try {
-            final Matcher matcher = STATUS_MEMORY_STATS.matcher(contents);
-            if (matcher.find()) {
-                final MemorySnapshot snapshot = new MemorySnapshot();
-                snapshot.uid = Integer.parseInt(matcher.group(1));
-                snapshot.rssHighWaterMarkInKilobytes = Integer.parseInt(matcher.group(2));
-                snapshot.rssInKilobytes = Integer.parseInt(matcher.group(3));
-                snapshot.anonRssInKilobytes = Integer.parseInt(matcher.group(4));
-                snapshot.swapInKilobytes = Integer.parseInt(matcher.group(5));
-                return snapshot;
-            }
-        } catch (NumberFormatException e) {
-            Slog.e(TAG, "Failed to parse value", e);
-        }
-        return null;
+        final MemorySnapshot snapshot = new MemorySnapshot();
+        snapshot.uid = (int) output[0];
+        snapshot.rssHighWaterMarkInKilobytes = (int) output[1];
+        snapshot.rssInKilobytes = (int) output[2];
+        snapshot.anonRssInKilobytes = (int) output[3];
+        snapshot.swapInKilobytes = (int) output[4];
+        return snapshot;
     }
 
     /**
@@ -78,31 +63,27 @@
      * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
      * if the file is not available.
      */
-    public static String readCmdlineFromProcfs(int pid) {
-        return parseCmdline(readFile("/proc/" + pid + "/cmdline"));
-    }
-
-    /**
-     * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
-     *
-     * Parsing is required to strip anything after the first null byte.
-     */
-    @VisibleForTesting
-    static String parseCmdline(String contents) {
-        int firstNullByte = contents.indexOf("\0");
-        if (firstNullByte == -1) {
-            return contents;
-        }
-        return contents.substring(0, firstNullByte);
-    }
-
-    private static String readFile(String path) {
-        try {
-            final File file = new File(path);
-            return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */);
-        } catch (IOException e) {
+    static String readCmdlineFromProcfs(int pid) {
+        String[] cmdline = new String[1];
+        if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) {
             return "";
         }
+        return cmdline[0];
+    }
+
+    static void forEachPid(BiConsumer<Integer, String> func) {
+        int[] pids = new int[1024];
+        pids = Process.getPids("/proc", pids);
+        for (int pid : pids) {
+            if (pid < 0) {
+                return;
+            }
+            String cmdline = readCmdlineFromProcfs(pid);
+            if (cmdline.isEmpty()) {
+                continue;
+            }
+            func.accept(pid, cmdline);
+        }
     }
 
     static final class MemorySnapshot {
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 2d36a0d..72a1b9d 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -18,6 +18,8 @@
 
 import android.Manifest;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -25,7 +27,12 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.IVold;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 import android.provider.MediaStore;
 import android.service.storage.ExternalStorageService;
@@ -47,27 +54,41 @@
 
     private final Object mLock = new Object();
     private final Context mContext;
-    private final Callback mCallback;
-    @GuardedBy("mLock")
-    private ComponentName mExternalStorageServiceComponent;
     @GuardedBy("mLock")
     private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
+    private final boolean mIsFuseEnabled;
 
-    public StorageSessionController(Context context, Callback callback) {
+    private volatile ComponentName mExternalStorageServiceComponent;
+    private volatile String mExternalStorageServicePackageName;
+    private volatile int mExternalStorageServiceAppId;
+    private volatile boolean mIsResetting;
+
+    public StorageSessionController(Context context, boolean isFuseEnabled) {
         mContext = Preconditions.checkNotNull(context);
-        mCallback = Preconditions.checkNotNull(callback);
+        mIsFuseEnabled = isFuseEnabled;
     }
 
     /**
-     * Starts a storage session associated with {@code deviceFd} for {@code vol}.
-     * Does nothing if a session is already started or starting. If the user associated with
-     * {@code vol} is not yet ready, the session will be retried {@link #onUserStarted}.
+     * Creates a storage session associated with {@code deviceFd} for {@code vol}. Sessions can be
+     * started with {@link #onVolumeReady} and removed with {@link #onVolumeUnmount} or
+     * {@link #onVolumeRemove}.
      *
-     * A session must be ended with {@link #endSession} when no longer required.
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     *
+     * @throws IllegalStateException if a session has already been created for {@code vol}
      */
-    public void onVolumeMounted(int userId, FileDescriptor deviceFd, VolumeInfo vol) {
+    public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol) {
+        if (!shouldHandle(vol)) {
+            return;
+        }
+
+        Slog.i(TAG, "On volume mount " + vol);
+
+        String sessionId = vol.getId();
+        int userId = vol.getMountUserId();
+
         if (deviceFd == null) {
-            Slog.w(TAG, "Null device fd. Session not started for " + vol);
+            Slog.w(TAG, "Null fd. Session not started for vol: " + vol);
             return;
         }
 
@@ -82,136 +103,320 @@
         }
 
         if ("/dev/null".equals(realPath)) {
-            Slog.i(TAG, "Volume ready for use: " + vol);
+            Slog.i(TAG, "Volume ready for use with id: " + sessionId);
             return;
         }
 
         synchronized (mLock) {
             StorageUserConnection connection = mConnections.get(userId);
             if (connection == null) {
-                Slog.i(TAG, "Creating new session for vol: " + vol);
                 connection = new StorageUserConnection(mContext, userId, this);
                 mConnections.put(userId, connection);
             }
-            try {
-                Slog.i(TAG, "Starting session for vol: " + vol);
-                connection.startSession(deviceFd, vol);
-            } catch (ExternalStorageServiceException e) {
-                Slog.e(TAG, "Failed to start session for vol: " + vol, e);
+            Slog.i(TAG, "Creating session with id: " + sessionId);
+            connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd));
+        }
+    }
+
+    /**
+     * Starts a storage session associated with {@code vol} after {@link #onVolumeMount}.
+     *
+     * Subsequent calls will attempt to start the storage session, but does nothing if already
+     * started. If the user associated with {@code vol} is not yet ready, all pending sesssions
+     * can be restarted with {@link onUnlockUser}.
+     *
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     *
+     * Blocks until the session is started or fails
+     *
+     * @throws ExternalStorageServiceException if the session fails to start
+     */
+    public void onVolumeReady(VolumeInfo vol) throws ExternalStorageServiceException {
+        if (!shouldHandle(vol)) {
+            return;
+        }
+
+        Slog.i(TAG, "On volume ready " + vol);
+        String sessionId = vol.getId();
+
+        StorageUserConnection connection = null;
+        synchronized (mLock) {
+            connection = mConnections.get(vol.getMountUserId());
+            if (connection == null) {
+                Slog.i(TAG, "Volume ready but no associated connection");
+                return;
+            }
+        }
+
+        connection.initSession(sessionId, vol.getPath().getPath(),
+                vol.getInternalPath().getPath());
+
+        if (isReady()) {
+            connection.startSession(sessionId);
+        } else {
+            Slog.i(TAG, "Controller not initialised, session not started " + sessionId);
+        }
+    }
+
+    /**
+     * Removes and returns the {@link StorageUserConnection} for {@code vol}.
+     *
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     *
+     * @return the connection that was removed or {@code null} if nothing was removed
+     */
+    @Nullable
+    public StorageUserConnection onVolumeRemove(VolumeInfo vol) {
+        if (!shouldHandle(vol)) {
+            return null;
+        }
+
+        Slog.i(TAG, "On volume remove " + vol);
+        String sessionId = vol.getId();
+        int userId = vol.getMountUserId();
+
+        synchronized (mLock) {
+            StorageUserConnection connection = mConnections.get(userId);
+            if (connection != null) {
+                Slog.i(TAG, "Removed session for vol with id: " + sessionId);
+                connection.removeSession(sessionId);
+                return connection;
+            } else {
+                Slog.w(TAG, "Session already removed for vol with id: " + sessionId);
+                return null;
+            }
+        }
+    }
+
+
+    /**
+     * Removes a storage session for {@code vol} and waits for exit.
+     *
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     *
+     * Any errors are ignored
+     *
+     * Call {@link #onVolumeRemove} to remove the connection without waiting for exit
+     */
+    public void onVolumeUnmount(VolumeInfo vol) {
+        StorageUserConnection connection = onVolumeRemove(vol);
+
+        Slog.i(TAG, "On volume unmount " + vol);
+        if (connection != null) {
+            String sessionId = vol.getId();
+
+            if (isReady()) {
+                try {
+                    connection.removeSessionAndWait(sessionId);
+                } catch (ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to end session for vol with id: " + sessionId, e);
+                }
+            } else {
+                Slog.i(TAG, "Controller not initialised, session not ended " + sessionId);
             }
         }
     }
 
     /**
-     * Ends a storage session for {@code vol}. Does nothing if the session is already
-     * ended or ending. Ending a session discards all resources associated with that session.
+     * Restarts all sessions for {@code userId}.
+     *
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     *
+     * This call blocks and waits for all sessions to be started, however any failures when starting
+     * a session will be ignored.
      */
-    public void onVolumeUnmounted(int userId, VolumeInfo vol) {
+    public void onUnlockUser(int userId) throws ExternalStorageServiceException {
+        if (!shouldHandle(null)) {
+            return;
+        }
+
+        Slog.i(TAG, "On user unlock " + userId);
+        if (userId == 0) {
+            init();
+        }
+
+        StorageUserConnection connection = null;
         synchronized (mLock) {
-            StorageUserConnection connection = mConnections.get(userId);
-            if (connection != null) {
-                Slog.i(TAG, "Ending session for vol: " + vol);
-                try {
-                    if (connection.endSession(vol)) {
-                        mConnections.remove(userId);
-                    }
-                } catch (ExternalStorageServiceException e) {
-                    Slog.e(TAG, "Failed to end session for vol: " + vol, e);
-                }
-            } else {
-                Slog.w(TAG, "Session already ended for vol: " + vol);
-            }
+            connection = mConnections.get(userId);
+        }
+
+        if (connection != null) {
+            Slog.i(TAG, "Restarting all sessions for user: " + userId);
+            connection.startAllSessions();
+        } else {
+            Slog.w(TAG, "No connection found for user: " + userId);
         }
     }
 
-    /** Restarts all sessions for {@code userId}. */
-    public void onUserStarted(int userId) {
-        synchronized (mLock) {
-            StorageUserConnection connection = mConnections.get(userId);
-            if (connection != null) {
-                try {
-                    Slog.i(TAG, "Restarting all sessions for user: " + userId);
-                    connection.startAllSessions();
-                } catch (ExternalStorageServiceException e) {
-                    Slog.e(TAG, "Failed to start all sessions", e);
-                }
-            } else {
-                // TODO(b/135341433): What does this mean in multi-user
+    /**
+     * Resets all sessions for all users and waits for exit. This may kill the
+     * {@link ExternalStorageservice} for a user if necessary to ensure all state has been reset.
+     *
+     * Does nothing if {@link #shouldHandle} is {@code false}
+     **/
+    public void onReset(IVold vold, Handler handler) {
+        if (!shouldHandle(null)) {
+            return;
+        }
+
+        if (!isReady()) {
+            synchronized (mLock) {
+                mConnections.clear();
             }
+            return;
+        }
+
+        SparseArray<StorageUserConnection> connections = new SparseArray();
+        synchronized (mLock) {
+            mIsResetting = true;
+            Slog.i(TAG, "Started resetting external storage service...");
+            for (int i = 0; i < mConnections.size(); i++) {
+                connections.put(mConnections.keyAt(i), mConnections.valueAt(i));
+            }
+        }
+
+        for (int i = 0; i < connections.size(); i++) {
+            StorageUserConnection connection = connections.valueAt(i);
+            for (String sessionId : connection.getAllSessionIds()) {
+                try {
+                    Slog.i(TAG, "Unmounting " + sessionId);
+                    vold.unmount(sessionId);
+                    Slog.i(TAG, "Unmounted " + sessionId);
+                } catch (ServiceSpecificException | RemoteException e) {
+                    // TODO(b/140025078): Hard reset vold?
+                    Slog.e(TAG, "Failed to unmount volume: " + sessionId, e);
+                }
+
+                try {
+                    Slog.i(TAG, "Exiting " + sessionId);
+                    connection.removeSessionAndWait(sessionId);
+                    Slog.i(TAG, "Exited " + sessionId);
+                } catch (IllegalStateException | ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to exit session: " + sessionId
+                            + ". Killing MediaProvider...", e);
+                    // If we failed to confirm the session exited, it is risky to proceed
+                    // We kill the ExternalStorageService as a last resort
+                    killExternalStorageService(connections.keyAt(i));
+                    break;
+                }
+            }
+            connection.close();
+        }
+
+        handler.removeCallbacksAndMessages(null);
+        synchronized (mLock) {
+            mConnections.clear();
+            mIsResetting = false;
+            Slog.i(TAG, "Finished resetting external storage service");
         }
     }
 
-    /** Ends all sessions for {@code userId}. */
-    public void onUserRemoved(int userId) {
-        synchronized (mLock) {
-            StorageUserConnection connection = mConnections.get(userId);
-            if (connection != null) {
-                try {
-                    Slog.i(TAG, "Ending all sessions for user: " + userId);
-                    connection.endAllSessions();
-                    mConnections.remove(userId);
-                } catch (ExternalStorageServiceException e) {
-                    Slog.e(TAG, "Failed to end all sessions", e);
-                }
-            } else {
-                // TODO(b/135341433): What does this mean in multi-user
-            }
+    private void init() throws ExternalStorageServiceException {
+        Slog.i(TAG, "Initialialising...");
+        ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
+                MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                | PackageManager.MATCH_SYSTEM_ONLY);
+        if (provider == null) {
+            throw new ExternalStorageServiceException("No valid MediaStore provider found");
         }
+
+        mExternalStorageServicePackageName = provider.applicationInfo.packageName;
+        mExternalStorageServiceAppId = UserHandle.getAppId(provider.applicationInfo.uid);
+
+        Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
+        intent.setPackage(mExternalStorageServicePackageName);
+        ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            throw new ExternalStorageServiceException(
+                    "No valid ExternalStorageService component found");
+        }
+
+        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+        ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+        if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
+                .equals(serviceInfo.permission)) {
+            throw new ExternalStorageServiceException(name.flattenToShortString()
+                    + " does not require permission "
+                    + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
+        }
+
+        mExternalStorageServiceComponent = name;
     }
 
     /** Returns the {@link ExternalStorageService} component name. */
     @Nullable
     public ComponentName getExternalStorageServiceComponentName() {
-        synchronized (mLock) {
-            if (mExternalStorageServiceComponent == null) {
-                ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
-                        MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                        | PackageManager.MATCH_SYSTEM_ONLY);
+        return mExternalStorageServiceComponent;
+    }
 
-                if (provider == null) {
-                    Slog.e(TAG, "No valid MediaStore provider found.");
-                }
-                String packageName = provider.applicationInfo.packageName;
-
-                Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
-                intent.setPackage(packageName);
-                ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
-                        PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
-                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
-                    Slog.e(TAG, "No valid ExternalStorageService component found.");
-                    return null;
-                }
-
-                ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-                ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
-                if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
-                        .equals(serviceInfo.permission)) {
-                    Slog.e(TAG, name.flattenToShortString() + " does not require permission "
-                            + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
-                    return null;
-                }
-                mExternalStorageServiceComponent = name;
-            }
-            return mExternalStorageServiceComponent;
+    private void killExternalStorageService(int userId) {
+        IActivityManager am = ActivityManager.getService();
+        try {
+            am.killApplication(mExternalStorageServicePackageName, mExternalStorageServiceAppId,
+                    userId, "storage_session_controller reset");
+        } catch (RemoteException e) {
+            Slog.i(TAG, "Failed to kill the ExtenalStorageService for user " + userId);
         }
     }
 
-    /** Returns the {@link StorageManagerService} callback. */
-    public Callback getCallback() {
-        return mCallback;
+    /**
+     * 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);
     }
 
-    /** Callback to listen to session events from the {@link StorageSessionController}. */
-    public interface Callback {
-        /** Called when a {@link StorageUserConnection} is disconnected. */
-        void onUserDisconnected(int userId);
+    /**
+     * Returns {@code true} if {@code vol} is an emulated or public volume,
+     * {@code false} otherwise
+     **/
+    public static boolean isEmulatedOrPublic(VolumeInfo vol) {
+        return vol.type == VolumeInfo.TYPE_EMULATED || vol.type == VolumeInfo.TYPE_PUBLIC;
     }
 
-    /** Exception thrown when communication with the {@link ExternalStorageService}. */
+    /** Exception thrown when communication with the {@link ExternalStorageService} fails. */
     public static class ExternalStorageServiceException extends Exception {
         public ExternalStorageServiceException(Throwable cause) {
             super(cause);
         }
+
+        public ExternalStorageServiceException(String message) {
+            super(message);
+        }
+
+        public ExternalStorageServiceException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    private boolean shouldHandle(@Nullable VolumeInfo vol) {
+        return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+    }
+
+    private boolean isReady() {
+        return mExternalStorageServiceComponent != null;
     }
 }
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index ff9c900..24b56a4 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -33,29 +33,31 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
 import android.os.RemoteCallback;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.storage.VolumeInfo;
 import android.service.storage.ExternalStorageService;
 import android.service.storage.IExternalStorageService;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
- * for a user and manages storage sessions represented by a {@link Session}.
+ * for a user and manages storage sessions associated with mounted volumes.
  */
 public final class StorageUserConnection {
     private static final String TAG = "StorageUserConnection";
+    private static final int REMOTE_TIMEOUT_SECONDS = 15;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -70,68 +72,188 @@
         mSessionController = controller;
     }
 
-    /** Starts a session for a user */
-    public void startSession(FileDescriptor deviceFd, VolumeInfo vol)
-            throws ExternalStorageServiceException {
-        String sessionId = vol.getId();
-        String upperPath = vol.getPath().getPath();
-        String lowerPath = vol.getInternalPath().getPath();
-        Slog.i(TAG, "Starting session with id: " + sessionId + " and upperPath: " + upperPath
-                + " and lowerPath: " + lowerPath);
-        Session session = new Session(sessionId, deviceFd, upperPath, lowerPath);
+    /**
+     * Creates and stores a storage {@link Session}.
+     *
+     * Created sessions must be initialised with {@link #initSession} before starting with
+     * {@link #startSession}.
+     *
+     * They must also be cleaned up with {@link #removeSession}.
+     *
+     * @throws IllegalArgumentException if a {@code Session} with {@code sessionId} already exists
+     */
+    public void createSession(String sessionId, ParcelFileDescriptor pfd) {
+        Preconditions.checkNotNull(sessionId);
+        Preconditions.checkNotNull(pfd);
+
         synchronized (mLock) {
-            // TODO(b/135341433): Ensure we don't replace a session without ending the previous
-            mSessions.put(sessionId, session);
-            // TODO(b/135341433): If this fails, maybe its at boot, how to handle if not boot?
+            Preconditions.checkArgument(!mSessions.containsKey(sessionId));
+            mSessions.put(sessionId, new Session(sessionId, pfd));
+        }
+    }
+
+    /**
+     * Initialise a storage {@link Session}.
+     *
+     * Initialised sessions can be started with {@link #startSession}.
+     *
+     * They must also be cleaned up with {@link #removeSession}.
+     *
+     * @throws IllegalArgumentException if {@code sessionId} does not exist or is initialised
+     */
+    public void initSession(String sessionId, String upperPath, String lowerPath) {
+        synchronized (mLock) {
+            Session session = mSessions.get(sessionId);
+            if (session == null) {
+                throw new IllegalStateException("Failed to initialise non existent session. Id: "
+                        + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath);
+            } else if (session.isInitialisedLocked()) {
+                throw new IllegalStateException("Already initialised session. Id: "
+                        + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath);
+            } else {
+                session.upperPath = upperPath;
+                session.lowerPath = lowerPath;
+                Slog.i(TAG, "Initialised session: " + session);
+            }
+        }
+    }
+
+    /**
+     * Starts an already created storage {@link Session} for {@code sessionId}.
+     *
+     * It is safe to call this multiple times, however if the session is already started,
+     * subsequent calls will be ignored.
+     *
+     * @throws ExternalStorageServiceException if the session failed to start
+     **/
+    public void startSession(String sessionId) throws ExternalStorageServiceException {
+        Session session;
+        synchronized (mLock) {
+            session = mSessions.get(sessionId);
+        }
+
+        prepareRemote();
+        synchronized (mLock) {
             mActiveConnection.startSessionLocked(session);
         }
     }
 
     /**
-     * Ends a session for a user.
+     * Removes a session without ending it or waiting for exit.
      *
-     * @return {@code true} if there are no more sessions for this user, {@code false} otherwise
+     * This should only be used if the session has certainly been ended because the volume was
+     * unmounted or the user running the session has been stopped. Otherwise, wait for session
+     * with {@link #waitForExit}.
      **/
-    public boolean endSession(VolumeInfo vol) throws ExternalStorageServiceException {
+    public Session removeSession(String sessionId) {
         synchronized (mLock) {
-            Session session = mSessions.remove(vol.getId());
+            Session session = mSessions.remove(sessionId);
             if (session != null) {
-                mActiveConnection.endSessionLocked(session);
-                mSessions.remove(session.sessionId);
+                session.close();
+                return session;
             }
-            boolean isAllSessionsEnded = mSessions.isEmpty();
-            if (isAllSessionsEnded) {
-                mActiveConnection.close();
-            }
-            return isAllSessionsEnded;
+            return null;
         }
     }
 
-    /** Starts all available sessions for a user */
-    public void startAllSessions() throws ExternalStorageServiceException {
+
+    /**
+     * Removes a session and waits for exit
+     *
+     * @throws ExternalStorageServiceException if the session may not have exited
+     **/
+    public void removeSessionAndWait(String sessionId) throws ExternalStorageServiceException {
+        Session session = removeSession(sessionId);
+        if (session == null) {
+            Slog.i(TAG, "No session found for id: " + sessionId);
+            return;
+        }
+
+        Slog.i(TAG, "Waiting for session end " + session + " ...");
+        prepareRemote();
         synchronized (mLock) {
+            mActiveConnection.endSessionLocked(session);
+        }
+    }
+
+    /** Starts all available sessions for a user without blocking. Any failures will be ignored. */
+    public void startAllSessions() {
+        try {
+            prepareRemote();
+        } catch (ExternalStorageServiceException e) {
+            Slog.e(TAG, "Failed to start all sessions for user: " + mUserId, e);
+            return;
+        }
+
+        synchronized (mLock) {
+            Slog.i(TAG, "Starting " + mSessions.size() + " sessions for user: " + mUserId + "...");
             for (Session session : mSessions.values()) {
-                mActiveConnection.startSessionLocked(session);
+                try {
+                    mActiveConnection.startSessionLocked(session);
+                } catch (IllegalStateException | ExternalStorageServiceException e) {
+                    // TODO: Don't crash process? We could get into process crash loop
+                    Slog.e(TAG, "Failed to start " + session, e);
+                }
             }
         }
     }
 
-    /** Ends all available sessions for a user */
-    public void endAllSessions() throws ExternalStorageServiceException {
+    /**
+     * Closes the connection to the {@link ExternalStorageService}. The connection will typically
+     * be restarted after close.
+     */
+    public void close() {
+        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()) {
-                mActiveConnection.endSessionLocked(session);
-                mSessions.remove(session.sessionId);
+                if (session.upperPath != null && path.startsWith(session.upperPath)) {
+                    if (mActiveConnection.isActiveLocked(session)) {
+                        return;
+                    }
+                }
             }
-            mActiveConnection.close();
+            throw new IllegalStateException("Path not ready " + path);
+        }
+    }
+
+    /** Returns all created sessions. */
+    public Set<String> getAllSessionIds() {
+        synchronized (mLock) {
+            return new HashSet<>(mSessions.keySet());
+        }
+    }
+
+    private void prepareRemote() throws ExternalStorageServiceException {
+        try {
+            waitForLatch(mActiveConnection.bind(), "remote_prepare_user " + mUserId);
+        } catch (IllegalStateException | TimeoutException e) {
+            throw new ExternalStorageServiceException("Failed to prepare remote", e);
+        }
+    }
+
+    private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
+        try {
+            if (!latch.await(REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+                // TODO(b/140025078): Call ActivityManager ANR API?
+                throw new TimeoutException("Latch wait for " + reason + " elapsed");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException("Latch wait for " + reason + " interrupted");
         }
     }
 
     private final class ActiveConnection implements AutoCloseable {
         // Lifecycle connection to the external storage service, needed to unbind.
-        // We should only try to bind if mServiceConnection is null.
-        // Non-null indicates we are connected or connecting.
         @GuardedBy("mLock") @Nullable private ServiceConnection mServiceConnection;
+        // True if we are connecting, either bound or binding
+        // False && mRemote != null means we are connected
+        // False && mRemote == null means we are neither connecting nor connected
+        @GuardedBy("mLock") @Nullable private boolean mIsConnecting;
         // Binder object representing the external storage service.
         // Non-null indicates we are connected
         @GuardedBy("mLock") @Nullable private IExternalStorageService mRemote;
@@ -141,58 +263,72 @@
         // (and clear the exception state) with the same lock which we hold during
         // the entire transaction, there is no risk of race.
         @GuardedBy("mLock") @Nullable private ParcelableException mLastException;
+        // Not guarded by any lock intentionally and non final because we cannot
+        // reset latches so need to create a new one after one use
+        private CountDownLatch mLatch;
 
         @Override
         public void close() {
+            ServiceConnection oldConnection = null;
             synchronized (mLock) {
-                if (mServiceConnection != null) {
-                    mContext.unbindService(mServiceConnection);
-                }
+                Slog.i(TAG, "Closing connection for user " + mUserId);
+                mIsConnecting = false;
+                oldConnection = mServiceConnection;
                 mServiceConnection = null;
                 mRemote = null;
             }
+
+            if (oldConnection != null) {
+                mContext.unbindService(oldConnection);
+            }
+        }
+
+        public boolean isActiveLocked(Session session) {
+            if (!session.isInitialisedLocked()) {
+                Slog.i(TAG, "Session not initialised " + session);
+                return false;
+            }
+
+            if (mRemote == null) {
+                throw new IllegalStateException("Valid session with inactive connection");
+            }
+            return true;
         }
 
         public void startSessionLocked(Session session) throws ExternalStorageServiceException {
-            if (mServiceConnection == null || mRemote == null) {
-                if (mServiceConnection == null) {
-                    // Not bound
-                    bindLocked();
-                } // else we are binding. In any case when we bind we'll re-start all sessions
+            if (!isActiveLocked(session)) {
                 return;
             }
 
             CountDownLatch latch = new CountDownLatch(1);
-            try {
+            try (ParcelFileDescriptor dupedPfd = session.pfd.dup()) {
                 mRemote.startSession(session.sessionId,
                         FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
-                        new ParcelFileDescriptor(session.deviceFd), session.upperPath,
-                        session.lowerPath, new RemoteCallback(result ->
+                        dupedPfd, session.upperPath, session.lowerPath, new RemoteCallback(result ->
                                 setResultLocked(latch, result)));
-
-            } catch (RemoteException e) {
-                throw new ExternalStorageServiceException(e);
+                waitForLatch(latch, "start_session " + session);
+                maybeThrowExceptionLocked();
+            } catch (Exception e) {
+                throw new ExternalStorageServiceException("Failed to start session: " + session, e);
             }
-            waitAndReturnResultLocked(latch);
         }
 
         public void endSessionLocked(Session session) throws ExternalStorageServiceException {
-            if (mRemote == null) {
-                // TODO(b/135341433): This assumes if there is no connection, there are no
-                // session resources held. Need to document in the ExternalStorageService
-                // API that implementors should end all sessions and clean up resources
-                // when the binding is lost, onDestroy?
+            session.close();
+            if (!isActiveLocked(session)) {
+                // Nothing to end, not started yet
                 return;
             }
 
             CountDownLatch latch = new CountDownLatch(1);
             try {
                 mRemote.endSession(session.sessionId, new RemoteCallback(result ->
-                                setResultLocked(latch, result)));
-            } catch (RemoteException e) {
-                throw new ExternalStorageServiceException(e);
+                        setResultLocked(latch, result)));
+                waitForLatch(latch, "end_session " + session);
+                maybeThrowExceptionLocked();
+            } catch (Exception e) {
+                throw new ExternalStorageServiceException("Failed to end session: " + session, e);
             }
-            waitAndReturnResultLocked(latch);
         }
 
         private void setResultLocked(CountDownLatch latch, Bundle result) {
@@ -200,36 +336,38 @@
             latch.countDown();
         }
 
-        private void waitAndReturnResultLocked(CountDownLatch latch)
-                throws ExternalStorageServiceException {
-            try {
-                // TODO(b/140025078): Call ActivityManager ANR API?
-                latch.await(20, TimeUnit.SECONDS);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                throw new IllegalStateException(
-                        "Interrupted while waiting for ExternalStorageService result");
-            }
+        private void maybeThrowExceptionLocked() throws IOException {
             if (mLastException != null) {
+                ParcelableException lastException = mLastException;
                 mLastException = null;
                 try {
-                    mLastException.maybeRethrow(IOException.class);
+                    lastException.maybeRethrow(IOException.class);
                 } catch (IOException e) {
-                    throw new ExternalStorageServiceException(e);
+                    throw e;
                 }
-                throw new RuntimeException(mLastException);
+                throw new RuntimeException(lastException);
             }
-            mLastException = null;
         }
 
-        private void bindLocked() {
+        public CountDownLatch bind() throws ExternalStorageServiceException {
             ComponentName name = mSessionController.getExternalStorageServiceComponentName();
             if (name == null) {
-                Slog.i(TAG, "Not ready to bind to the ExternalStorageService for user " + mUserId);
-                return;
+                // Not ready to bind
+                throw new ExternalStorageServiceException(
+                        "Not ready to bind to the ExternalStorageService for user " + mUserId);
             }
 
-            ServiceConnection connection = new ServiceConnection() {
+            synchronized (mLock) {
+                if (mRemote != null || mIsConnecting) {
+                    // Connected or connecting (bound or binding)
+                    // Will wait on a latch that will countdown when we connect, unless we are
+                    // connected and the latch has already countdown, yay!
+                    return mLatch;
+                } // else neither connected nor connecting
+
+                mLatch = new CountDownLatch(1);
+                mIsConnecting = true;
+                mServiceConnection = new ServiceConnection() {
                     @Override
                     public void onServiceConnected(ComponentName name, IBinder service) {
                         Slog.i(TAG, "Service: [" + name + "] connected. User [" + mUserId + "]");
@@ -255,65 +393,81 @@
 
                     @Override
                     public void onNullBinding(ComponentName name) {
-                        // Should never happen. Service returned null from #onBind.
                         Slog.wtf(TAG, "Service: [" + name + "] is null. User [" + mUserId + "]");
                     }
 
                     private void handleConnection(IBinder service) {
                         synchronized (mLock) {
-                            if (mServiceConnection != null) {
+                            if (mIsConnecting) {
                                 mRemote = IExternalStorageService.Stub.asInterface(service);
-                            } else {
-                                Slog.wtf(TAG, "Service connected without a connection object??");
+                                mIsConnecting = false;
+                                mLatch.countDown();
+                                // Separate thread so we don't block the main thead
+                                return;
                             }
                         }
-
-                        try {
-                            startAllSessions();
-                        } catch (ExternalStorageServiceException e) {
-                            Slog.e(TAG, "Failed to start all sessions", e);
-                        }
+                        Slog.wtf(TAG, "Connection closed to the ExternalStorageService for user "
+                                + mUserId);
                     }
 
                     private void handleDisconnection() {
-                        close();
                         // Clear all sessions because we will need a new device fd since
                         // StorageManagerService will reset the device mount state and #startSession
                         // will be called for any required mounts.
-                        synchronized (mLock) {
-                            mSessions.clear();
-                        }
                         // Notify StorageManagerService so it can restart all necessary sessions
-                        mSessionController.getCallback().onUserDisconnected(mUserId);
+                        close();
+                        new Thread(StorageUserConnection.this::startAllSessions).start();
                     }
                 };
+            }
 
             Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
-            // TODO(b/135341433): Verify required service flags BIND_IMPORTANT?
-            if (mContext.bindServiceAsUser(new Intent().setComponent(name), connection,
-                            Context.BIND_AUTO_CREATE, UserHandle.of(mUserId))) {
+            if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
+                            Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+                            UserHandle.of(mUserId))) {
                 Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
-                mServiceConnection = connection;
-                // Reset the remote, we will set when we connect
-                mRemote = null;
+                return mLatch;
             } else {
-                Slog.w(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
+                synchronized (mLock) {
+                    mIsConnecting = false;
+                }
+                throw new ExternalStorageServiceException(
+                        "Failed to bind to the ExternalStorageService for user " + mUserId);
             }
         }
     }
 
-    private static final class Session {
+    private static final class Session implements AutoCloseable {
         public final String sessionId;
-        public final FileDescriptor deviceFd;
-        public final String lowerPath;
-        public final String upperPath;
+        public final ParcelFileDescriptor pfd;
+        @GuardedBy("mLock")
+        public String lowerPath;
+        @GuardedBy("mLock")
+        public String upperPath;
 
-        Session(String sessionId, FileDescriptor deviceFd, String upperPath,
-                String lowerPath) {
+        Session(String sessionId, ParcelFileDescriptor pfd) {
             this.sessionId = sessionId;
-            this.upperPath = upperPath;
-            this.lowerPath = lowerPath;
-            this.deviceFd = deviceFd;
+            this.pfd = pfd;
+        }
+
+        @Override
+        public void close() {
+            try {
+                pfd.close();
+            } catch (IOException e) {
+                Slog.i(TAG, "Failed to close session: " + this);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "[SessionId: " + sessionId + ". UpperPath: " + upperPath + ". LowerPath: "
+                    + lowerPath + "]";
+        }
+
+        @GuardedBy("mLock")
+        public boolean isInitialisedLocked() {
+            return !TextUtils.isEmpty(upperPath) && !TextUtils.isEmpty(lowerPath);
         }
     }
 }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 4d0788f..7d905ba 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -120,7 +120,9 @@
             synchronized (mManagerService.mLock) {
                 UserState userState = mManagerService.peekUserStateLocked(userId);
                 if (userState != null) {
-                    userState.mConnection.cleanupService();
+                    if (userState.mConnection != null) {
+                        userState.mConnection.cleanupService();
+                    }
                     mManagerService.mUserStates.remove(userId);
                 }
             }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 7408dd4..5f5cd3c 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.KeyStore;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -135,6 +136,33 @@
     @GuardedBy("mUserIsTrusted")
     private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
 
+    /**
+     * Stores the locked state for users on the device. There are three different type of users
+     * which are handled slightly differently:
+     * <ul>
+     *  <li> Users with real keyguard
+     *  These are users who can be switched to ({@link UserInfo#supportsSwitchToByUser()}). Their
+     *  locked state is derived by a combination of user secure state, keyguard state, trust agent
+     *  decision and biometric authentication result. These are updated via
+     *  {@link #refreshDeviceLockedForUser(int)} and result stored in {@link #mDeviceLockedForUser}.
+     *  <li> Managed profiles with unified challenge
+     *  Managed profile with unified challenge always shares the same locked state as their parent,
+     *  so their locked state is not recorded in  {@link #mDeviceLockedForUser}. Instead,
+     *  {@link ITrustManager#isDeviceLocked(int)} always resolves their parent user handle and
+     *  queries its locked state instead.
+     *  <li> Managed profiles with separate challenge
+     *  Locked state for profile with separate challenge is determined by other parts of the
+     *  framework (mostly PowerManager) and pushed to TrustManagerService via
+     *  {@link ITrustManager#setDeviceLockedForUser(int, boolean)}. Although in a corner case when
+     *  the profile has a separate but empty challenge, setting its {@link #mDeviceLockedForUser} to
+     *  {@code false} is actually done by {@link #refreshDeviceLockedForUser(int)}.
+     * </ul>
+     * TODO: Rename {@link ITrustManager#setDeviceLockedForUser(int, boolean)} to
+     * {@code setDeviceLockedForProfile} to better reflect its purpose. Unifying
+     * {@code setDeviceLockedForProfile} and {@link #setDeviceLockedForUser} would also be nice.
+     * At the moment they both update {@link #mDeviceLockedForUser} but have slightly different
+     * side-effects: one notifies trust agents while the other sends out a broadcast.
+     */
     @GuardedBy("mDeviceLockedForUser")
     private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
 
@@ -601,6 +629,10 @@
         }
     }
 
+    /**
+     * Update the user's locked state. Only applicable to users with a real keyguard
+     * ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles.
+     */
     private void refreshDeviceLockedForUser(int userId) {
         if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
             Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle,"
@@ -661,6 +693,15 @@
         }
         if (changed) {
             dispatchDeviceLocked(userId, locked);
+
+            KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+            // Also update the user's profiles who have unified challenge, since they
+            // share the same unlocked state (see {@link #isDeviceLocked(int)})
+            for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
+                if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+                    KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
+                }
+            }
         }
     }
 
@@ -1194,6 +1235,10 @@
             return "0x" + Integer.toHexString(i);
         }
 
+        /**
+         * Changes the lock status for the given user. This is only applicable to managed profiles,
+         * other users should be handled by Keyguard.
+         */
         @Override
         public void setDeviceLockedForUser(int userId, boolean locked) {
             enforceReportPermission();
@@ -1204,6 +1249,9 @@
                     synchronized (mDeviceLockedForUser) {
                         mDeviceLockedForUser.put(userId, locked);
                     }
+
+                    KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+
                     if (locked) {
                         try {
                             ActivityManager.getService().notifyLockedProfile(userId);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 73c20a7..ebfc65e 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -180,6 +180,7 @@
         mDisplayContent.reconfigureDisplayLocked();
         onRequestedOverrideConfigurationChanged(
                 mDisplayContent.getRequestedOverrideConfiguration());
+        mService.mWindowManager.mDisplayNotificationController.dispatchDisplayAdded(this);
     }
 
     void onDisplayChanged() {
@@ -213,7 +214,7 @@
         if (position == POSITION_BOTTOM) {
             position = 0;
         } else if (toTop) {
-            position = mStacks.size();
+            position = getChildCount();
         }
         if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
                 + " to displayId=" + mDisplayId + " position=" + position);
@@ -253,7 +254,7 @@
 
     void positionChildAtTop(ActivityStack stack, boolean includingParents,
             String updateLastFocusedStackReason) {
-        positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason);
+        positionChildAt(stack, getChildCount(), includingParents, updateLastFocusedStackReason);
     }
 
     void positionChildAtBottom(ActivityStack stack) {
@@ -288,7 +289,7 @@
         // 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 >= mStacks.size() - 1 && stack.isFocusableAndVisible()) {
+        if (wasContained && position >= getChildCount() - 1 && stack.isFocusableAndVisible()) {
             mPreferredTopFocusableStack = stack;
         } else if (mPreferredTopFocusableStack == stack) {
             mPreferredTopFocusableStack = null;
@@ -314,14 +315,14 @@
     }
 
     private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
-        int position = mStacks.size();
+        int position = getChildCount();
         if (stack.inPinnedWindowingMode()) {
             // Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
             // just return the candidate position.
             return Math.min(position, candidatePosition);
         }
         while (position > 0) {
-            final ActivityStack targetStack = mStacks.get(position - 1);
+            final ActivityStack targetStack = getChildAt(position - 1);
             if (!targetStack.isAlwaysOnTop()) {
                 // We reached a stack that isn't always-on-top.
                 break;
@@ -336,8 +337,8 @@
     }
 
     <T extends ActivityStack> T getStack(int stackId) {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getChildAt(i);
             if (stack.mStackId == stackId) {
                 return (T) stack;
             }
@@ -362,8 +363,8 @@
             return (T) mSplitScreenPrimaryStack;
         }
 
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getChildAt(i);
             if (stack.isCompatible(windowingMode, activityType)) {
                 return (T) stack;
             }
@@ -489,8 +490,8 @@
             return mPreferredTopFocusableStack;
         }
 
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getChildAt(i);
             if (stack.isFocusableAndVisible()) {
                 return stack;
             }
@@ -504,8 +505,8 @@
                 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
 
         ActivityStack candidate = null;
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getChildAt(i);
             if (ignoreCurrent && stack == currentFocus) {
                 continue;
             }
@@ -560,8 +561,8 @@
     }
 
     boolean allResumedActivitiesComplete() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = mStacks.get(stackNdx).getResumedActivity();
+        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityRecord r = getChildAt(stackNdx).getResumedActivity();
             if (r != null && !r.isState(RESUMED)) {
                 return false;
             }
@@ -587,8 +588,8 @@
      */
     boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
         boolean someActivityPaused = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getChildAt(stackNdx);
             final ActivityRecord resumedActivity = stack.getResumedActivity();
             if (resumedActivity != null
                     && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
@@ -652,8 +653,8 @@
         final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = windowingModes.length - 1 ; j >= 0; --j) {
             final int windowingMode = windowingModes[j];
-            for (int i = mStacks.size() - 1; i >= 0; --i) {
-                final ActivityStack stack = mStacks.get(i);
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getChildAt(i);
                 if (!stack.isActivityTypeStandardOrUndefined()) {
                     continue;
                 }
@@ -680,8 +681,8 @@
         final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = activityTypes.length - 1 ; j >= 0; --j) {
             final int activityType = activityTypes[j];
-            for (int i = mStacks.size() - 1; i >= 0; --i) {
-                final ActivityStack stack = mStacks.get(i);
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getChildAt(i);
                 if (stack.getActivityType() == activityType) {
                     stacks.add(stack);
                 }
@@ -752,8 +753,8 @@
         mService.deferWindowLayout();
         try {
             // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
-            for (int i = mStacks.size() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = mStacks.get(i);
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getChildAt(i);
                 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                     continue;
                 }
@@ -781,8 +782,8 @@
         mService.deferWindowLayout();
         try {
             // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
-            for (int i = mStacks.size() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = mStacks.get(i);
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getChildAt(i);
                 if (otherStack == mSplitScreenPrimaryStack
                         || !otherStack.affectedBySplitScreenResize()) {
                     continue;
@@ -930,7 +931,7 @@
      * some stacks are not focusable (e.g. PiP).
      */
     ActivityStack getTopStack() {
-        return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
+        return mStacks.isEmpty() ? null : getChildAt(getChildCount() - 1);
     }
 
     boolean isTopStack(ActivityStack stack) {
@@ -938,8 +939,8 @@
     }
 
     boolean isTopNotPinnedStack(ActivityStack stack) {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack current = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack current = getChildAt(i);
             if (!current.inPinnedWindowingMode()) {
                 return current == stack;
             }
@@ -948,8 +949,8 @@
     }
 
     ActivityStack getTopStackInWindowingMode(int windowingMode) {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack current = mStacks.get(i);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack current = getChildAt(i);
             if (windowingMode == current.getWindowingMode()) {
                 return current;
             }
@@ -979,8 +980,8 @@
 
         // Look in other focusable stacks.
         if (topRunning == null) {
-            for (int i = mStacks.size() - 1; i >= 0; --i) {
-                final ActivityStack stack = mStacks.get(i);
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getChildAt(i);
                 // Only consider focusable stacks other than the current focused one.
                 if (stack == focusedStack || !stack.isFocusable()) {
                     continue;
@@ -1112,8 +1113,8 @@
     }
 
     void onLockTaskPackagesUpdated() {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            mStacks.get(i).onLockTaskPackagesUpdated();
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            getChildAt(i).onLockTaskPackagesUpdated();
         }
     }
 
@@ -1165,7 +1166,7 @@
 
     @Override
     public String toString() {
-        return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+        return "ActivityDisplay={" + mDisplayId + " numStacks=" + getChildCount() + "}";
     }
 
     @Override
@@ -1224,10 +1225,10 @@
         final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
         mRootActivityContainer.mStackSupervisor.beginDeferResume();
         try {
-            int numStacks = mStacks.size();
+            int numStacks = getChildCount();
             // Keep the order from bottom to top.
             for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-                final ActivityStack stack = mStacks.get(stackNdx);
+                final ActivityStack stack = getChildAt(stackNdx);
                 // Always finish non-standard type stacks.
                 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
                     stack.finishAllActivitiesImmediately();
@@ -1244,8 +1245,8 @@
                 }
                 // Stacks may be removed from this display. Ensure each stack will be processed and
                 // the loop will end.
-                stackNdx -= numStacks - mStacks.size();
-                numStacks = mStacks.size();
+                stackNdx -= numStacks - getChildCount();
+                numStacks = getChildCount();
             }
         } finally {
             mRootActivityContainer.mStackSupervisor.endDeferResume();
@@ -1271,7 +1272,7 @@
             return;
         }
 
-        final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null;
+        final ActivityStack stack = getChildCount() == 1 ? getChildAt(0) : null;
         if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
             // 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
@@ -1348,7 +1349,7 @@
      */
     ActivityStack getStackAbove(ActivityStack stack) {
         final int stackIndex = mStacks.indexOf(stack) + 1;
-        return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
+        return (stackIndex < getChildCount()) ? getChildAt(stackIndex) : null;
     }
 
     /**
@@ -1365,9 +1366,9 @@
         positionChildAtBottom(stack);
 
         // Find the next position where the stack should be placed
-        final int numStacks = mStacks.size();
+        final int numStacks = getChildCount();
         for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-            final ActivityStack s = mStacks.get(stackNdx);
+            final ActivityStack s = getChildAt(stackNdx);
             if (s == stack) {
                 continue;
             }
@@ -1553,7 +1554,7 @@
     }
 
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
+        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getChildCount()
                 + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
         final String myPrefix = prefix + " ";
         if (mHomeStack != null) {
@@ -1577,8 +1578,8 @@
     }
 
     public void dumpStacks(PrintWriter pw) {
-        for (int i = mStacks.size() - 1; i >= 0; --i) {
-            pw.print(mStacks.get(i).mStackId);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            pw.print(getChildAt(i).mStackId);
             if (i > 0) {
                 pw.print(",");
             }
@@ -1601,8 +1602,8 @@
         } else {
             proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
         }
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getChildAt(stackNdx);
             stack.writeToProto(proto, STACKS, logLevel);
         }
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 73034b0..0a861ad 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -548,7 +548,7 @@
     private static boolean hasActivityToBeDrawn(Task t) {
         for (int i = t.getChildCount() - 1; i >= 0; --i) {
             final ActivityRecord r = t.getChildAt(i);
-            if (r.visible && !r.mDrawn && !r.finishing) {
+            if (r.mVisibleRequested && !r.mDrawn && !r.finishing) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 081bd2b..5b5ea21 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -121,6 +121,7 @@
 import static com.android.server.am.ActivityRecordProto.STATE;
 import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
 import static com.android.server.am.ActivityRecordProto.VISIBLE;
+import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED;
 import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
 import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
@@ -176,8 +177,6 @@
 import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT;
 import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT;
 import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
-import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
-import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
 import static com.android.server.wm.AppWindowTokenProto.IS_ANIMATING;
 import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
@@ -192,6 +191,7 @@
 import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
 import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
 import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
+import static com.android.server.wm.AppWindowTokenProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW;
 import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
@@ -462,13 +462,13 @@
     private boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
     int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
-    boolean visible;        // does this activity's window need to be shown?
+    private boolean mVisible;        // Should this token's windows be visible?
     boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
                                      // might hide this activity?
     // True if the hidden state of this token was forced to false due to a transferred starting
     // window.
-    private boolean mHiddenSetFromTransferredStartingWindow;
-    // TODO: figureout how to consolidate with the same variable in ActivityRecord.
+    private boolean mVisibleSetFromTransferredStartingWindow;
+    // TODO: figure out how to consolidate with the same variable in ActivityRecord.
     private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
                                         // process that it is hidden.
     private boolean mLastDeferHidingClient; // If true we will defer setting mClientHidden to true
@@ -622,11 +622,11 @@
     // case do not clear allDrawn until the animation completes.
     boolean deferClearAllDrawn;
 
-    // Is this window's surface needed?  This is almost like hidden, except
-    // it will sometimes be true a little earlier: when the token has
+    // Is this window's surface needed?  This is almost like visible, except
+    // it will sometimes be true a little earlier: when the activity record has
     // been shown, but is still waiting for its app transition to execute
     // before making its windows shown.
-    boolean hiddenRequested;
+    boolean mVisibleRequested;
 
     // Last visibility state we reported to the app token.
     boolean reportedVisible;
@@ -836,7 +836,6 @@
                 pw.print(" finishing="); pw.println(finishing);
         pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
                 pw.print(" inHistory="); pw.print(inHistory);
-                pw.print(" visible="); pw.print(visible);
                 pw.print(" sleeping="); pw.print(sleeping);
                 pw.print(" idle="); pw.print(idle);
                 pw.print(" mStartingWindowState=");
@@ -855,12 +854,14 @@
             pw.println(requestedVrComponent);
         }
         super.dump(pw, prefix, dumpAll);
+        pw.print(" visible="); pw.print(mVisible);
         if (appToken != null) {
             pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
         }
         pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent);
         pw.print(" mOrientation="); pw.println(mOrientation);
-        pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
+        pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
+                + " mClientHidden=" + mClientHidden
                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
                 + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
         if (paused) {
@@ -885,13 +886,13 @@
             pw.print(" mIsExiting="); pw.println(mIsExiting);
         }
         if (startingWindow != null || startingSurface != null
-                || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
+                || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
             pw.print(" startingSurface="); pw.print(startingSurface);
             pw.print(" startingDisplayed="); pw.print(startingDisplayed);
             pw.print(" startingMoved="); pw.print(startingMoved);
             pw.println(" mHiddenSetFromTransferredStartingWindow="
-                    + mHiddenSetFromTransferredStartingWindow);
+                    + mVisibleSetFromTransferredStartingWindow);
         }
         if (!mFrozenBounds.isEmpty()) {
             pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
@@ -1487,8 +1488,8 @@
         }
 
         // Application tokens start out hidden.
-        setHidden(true);
-        hiddenRequested = true;
+        setVisible(false);
+        mVisibleRequested = false;
 
         ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
                 ColorDisplayService.ColorDisplayServiceInternal.class);
@@ -1517,7 +1518,6 @@
         deferRelaunchUntilPaused = false;
         keysPaused = false;
         inHistory = false;
-        visible = false;
         nowVisible = false;
         mDrawn = false;
         idle = false;
@@ -2200,7 +2200,7 @@
      * 2. App is delayed closing since it might enter PIP.
      */
     boolean isClosingOrEnteringPip() {
-        return (isAnimating(TRANSITION | PARENTS) && hiddenRequested) || mWillCloseOrEnterPip;
+        return (isAnimating(TRANSITION | PARENTS) && !mVisibleRequested) || mWillCloseOrEnterPip;
     }
     /**
      * @return Whether AppOps allows this package to enter picture-in-picture.
@@ -2459,7 +2459,7 @@
                     mAtmService.getLockTaskController().clearLockedTask(task);
                 }
             } else if (!isState(PAUSING)) {
-                if (visible) {
+                if (mVisibleRequested) {
                     // Prepare and execute close transition.
                     prepareActivityHideTransitionAnimation(transit);
                 }
@@ -2538,12 +2538,13 @@
         // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
         final ActivityRecord next = getDisplay().topRunningActivity(
                 true /* considerKeyguardState */);
-        final boolean isVisible = visible || nowVisible;
+        final boolean isVisible = mVisibleRequested || nowVisible;
         // isNextNotYetVisible is to check if the next activity is invisible, or it has been
         // requested to be invisible but its windows haven't reported as invisible.  If so, it
         // implied that the current finishing activity should be added into stopping list rather
         // than destroy immediately.
-        final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible);
+        final boolean isNextNotYetVisible = next != null
+                && (!next.nowVisible || !next.mVisibleRequested);
         if (isVisible && isNextNotYetVisible) {
             // Add this activity to the list of stopping activities. It will be processed and
             // destroyed when the next activity reports idle.
@@ -2658,14 +2659,16 @@
         EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
                 System.identityHashCode(this), task.mTaskId, shortComponentName, reason);
 
+        final ActivityStack stack = getActivityStack();
+        if (hasProcess() && !stack.inLruList(this)) {
+            Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
+        }
+
         boolean removedFromHistory = false;
 
         cleanUp(false /* cleanServices */, false /* setState */);
 
-        final ActivityStack stack = getActivityStack();
-        final boolean hadApp = hasProcess();
-
-        if (hadApp) {
+        if (hasProcess()) {
             if (removeFromApp) {
                 app.removeActivity(this);
                 if (!app.hasActivities()) {
@@ -2730,10 +2733,6 @@
 
         configChangeFlags = 0;
 
-        if (!stack.removeActivityFromLRUList(this) && hadApp) {
-            Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
-        }
-
         return removedFromHistory;
     }
 
@@ -3213,7 +3212,7 @@
                         "Removing starting %s from %s", tStartingWindow, fromActivity);
                 fromActivity.removeChild(tStartingWindow);
                 fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
-                fromActivity.mHiddenSetFromTransferredStartingWindow = false;
+                fromActivity.mVisibleSetFromTransferredStartingWindow = false;
                 addWindow(tStartingWindow);
 
                 // Propagate other interesting state between the tokens. If the old token is displayed,
@@ -3226,10 +3225,10 @@
                 if (fromActivity.firstWindowDrawn) {
                     firstWindowDrawn = true;
                 }
-                if (!fromActivity.isHidden()) {
-                    setHidden(false);
-                    hiddenRequested = false;
-                    mHiddenSetFromTransferredStartingWindow = true;
+                if (fromActivity.isVisible()) {
+                    setVisible(true);
+                    mVisibleRequested = true;
+                    mVisibleSetFromTransferredStartingWindow = true;
                 }
                 setClientHidden(fromActivity.mClientHidden);
 
@@ -3277,7 +3276,7 @@
             if (fromActivity == this) {
                 return;
             }
-            if (fromActivity.hiddenRequested && transferStartingWindow(fromActivity.token)) {
+            if (!fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token)) {
                 return;
             }
         }
@@ -3792,6 +3791,10 @@
         return opts;
     }
 
+    boolean allowMoveToFront() {
+        return pendingOptions == null || !pendingOptions.getAvoidMoveToFront();
+    }
+
     void removeUriPermissionsLocked() {
         if (uriPermissions != null) {
             uriPermissions.removeUriPermissions();
@@ -3828,7 +3831,7 @@
             return;
         }
         mDeferHidingClient = deferHidingClient;
-        if (!mDeferHidingClient && !visible) {
+        if (!mDeferHidingClient && !mVisibleRequested) {
             // Hiding the client is no longer deferred and the app isn't visible still, go ahead and
             // update the visibility.
             setVisibility(false);
@@ -3839,7 +3842,14 @@
     boolean isVisible() {
         // If the activity isn't hidden then it is considered visible and there is no need to check
         // its children windows to see if they are visible.
-        return !isHidden();
+        return mVisible;
+    }
+
+    void setVisible(boolean visible) {
+        if (visible != mVisible) {
+            mVisible = visible;
+            scheduleAnimation();
+        }
     }
 
     void setVisibility(boolean visible) {
@@ -3848,20 +3858,17 @@
                     + appToken);
             return;
         }
+        if (visible) {
+            mDeferHidingClient = false;
+        }
         setVisibility(visible, mDeferHidingClient);
         mAtmService.addWindowLayoutReasons(
                 ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
         mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
-    }
-
-    // TODO: Look into merging with #commitVisibility()
-    void setVisible(boolean newVisible) {
-        visible = newVisible;
-        mDeferHidingClient = !visible && mDeferHidingClient;
-        setVisibility(visible);
         mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
+    @VisibleForTesting
     void setVisibility(boolean visible, boolean deferHidingClient) {
         final AppTransition appTransition = getDisplayContent().mAppTransition;
 
@@ -3872,7 +3879,7 @@
         // transition can be selected.
         // TODO: Probably a good idea to separate the concept of opening/closing apps from the
         // concept of setting visibility...
-        if (!visible && hiddenRequested) {
+        if (!visible && !mVisibleRequested) {
 
             if (!deferHidingClient && mLastDeferHidingClient) {
                 // We previously deferred telling the client to hide itself when visibility was
@@ -3884,8 +3891,8 @@
         }
 
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
-                appToken, visible, appTransition, isHidden(), hiddenRequested,
+                "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+                appToken, visible, appTransition, isVisible(), mVisibleRequested,
                 Debug.getCallers(6));
 
         final DisplayContent displayContent = getDisplayContent();
@@ -3896,7 +3903,7 @@
         }
         displayContent.mChangingApps.remove(this);
         waitingToShow = false;
-        hiddenRequested = !visible;
+        mVisibleRequested = visible;
         mLastDeferHidingClient = deferHidingClient;
 
         if (!visible) {
@@ -3915,11 +3922,11 @@
             startingMoved = false;
             // If the token is currently hidden (should be the common case), or has been
             // stopped, then we need to set up to wait for its windows to be ready.
-            if (isHidden() || mAppStopped) {
+            if (!isVisible() || mAppStopped) {
                 clearAllDrawn();
 
                 // If the app was already visible, don't reset the waitingToShow state.
-                if (isHidden()) {
+                if (!isVisible()) {
                     waitingToShow = true;
 
                     // If the client isn't hidden, we don't need to reset the drawing state.
@@ -3989,9 +3996,9 @@
             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
 
         boolean delayed = false;
-        // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
+        // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
         // been set by the app now.
-        mHiddenSetFromTransferredStartingWindow = false;
+        mVisibleSetFromTransferredStartingWindow = false;
 
         // Allow for state changes and animation to be applied if:
         // * token is transitioning visibility state
@@ -4001,7 +4008,7 @@
         // * or the token is the opening app and visible while opening task behind existing one.
         final DisplayContent displayContent = getDisplayContent();
         boolean visibilityChanged = false;
-        if (isHidden() == visible || (isHidden() && mIsExiting)
+        if (isVisible() != visible || (!isVisible() && mIsExiting)
                 || (visible && waitingForReplacement())
                 || (visible && displayContent.mOpeningApps.contains(this)
                 && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) {
@@ -4009,7 +4016,7 @@
                     mWmService.mAccessibilityController;
             boolean changed = false;
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                    "Changing app %s hidden=%b performLayout=%b", this, isHidden(),
+                    "Changing app %s visible=%b performLayout=%b", this, isVisible(),
                     performLayout);
 
             boolean runningAppAnimation = false;
@@ -4034,8 +4041,8 @@
                 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
             }
 
-            setHidden(!visible);
-            hiddenRequested = !visible;
+            setVisible(visible);
+            mVisibleRequested = visible;
             visibilityChanged = true;
             if (!visible) {
                 stopFreezingScreen(true, true);
@@ -4053,8 +4060,8 @@
             }
 
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
-                    "commitVisibility: %s: hidden=%b hiddenRequested=%b", this,
-                    isHidden(), hiddenRequested);
+                    "commitVisibility: %s: visible=%b visibleRequested=%b", this,
+                    isVisible(), mVisibleRequested);
 
             if (changed) {
                 displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
@@ -4118,7 +4125,7 @@
             // no animation but there will still be a transition set.
             // We still need to delay hiding the surface such that it
             // can be synchronized with showing the next surface in the transition.
-            if (isHidden() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
+            if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
                 SurfaceControl.openTransaction();
                 for (int i = mChildren.size() - 1; i >= 0; i--) {
                     mChildren.get(i).mWinAnimator.hide("immediately hidden");
@@ -4131,12 +4138,6 @@
     }
 
     @Override
-    void setHidden(boolean hidden) {
-        super.setHidden(hidden);
-        scheduleAnimation();
-    }
-
-    @Override
     void onAppTransitionDone() {
         sendingToBottom = false;
     }
@@ -4399,7 +4400,7 @@
                 updateOptionsLocked(returningOptions);
                 stack.mUndrawnActivitiesBelowTopTranslucent.add(this);
             }
-            setVisible(true);
+            setVisibility(true);
             sleeping = false;
             app.postPendingUiCleanMsg(true);
             if (reportToClient) {
@@ -4435,7 +4436,7 @@
     }
 
     void makeInvisible() {
-        if (!visible) {
+        if (!mVisibleRequested) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
             return;
         }
@@ -4457,7 +4458,7 @@
             final boolean deferHidingClient = canEnterPictureInPicture
                     && !isState(STOPPING, STOPPED, PAUSED);
             setDeferHidingClient(deferHidingClient);
-            setVisible(false);
+            setVisibility(false);
 
             switch (getState()) {
                 case STOPPING:
@@ -4644,8 +4645,8 @@
      * state to match that fact.
      */
     void completeResumeLocked() {
-        final boolean wasVisible = visible;
-        setVisible(true);
+        final boolean wasVisible = mVisibleRequested;
+        setVisibility(true);
         if (!wasVisible) {
             // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
             mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
@@ -4729,15 +4730,16 @@
             }
             setState(STOPPING, "stopIfPossible");
             if (DEBUG_VISIBILITY) {
-                Slog.v(TAG_VISIBILITY, "Stopping visible=" + visible + " for " + this);
+                Slog.v(TAG_VISIBILITY, "Stopping visibleRequested="
+                        + mVisibleRequested + " for " + this);
             }
-            if (!visible) {
-                setVisible(false);
+            if (!mVisibleRequested) {
+                setVisibility(false);
             }
             EventLogTags.writeAmStopActivity(
                     mUserId, System.identityHashCode(this), shortComponentName);
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
-                    StopActivityItem.obtain(visible, configChangeFlags));
+                    StopActivityItem.obtain(mVisibleRequested, configChangeFlags));
             if (stack.shouldSleepOrShutDownActivities()) {
                 setSleeping(true);
             }
@@ -4900,10 +4902,10 @@
 
     void startFreezingScreen() {
         ProtoLog.i(WM_DEBUG_ORIENTATION,
-                "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
-                appToken, isHidden(), mFreezingScreen, hiddenRequested,
+                "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+                appToken, isVisible(), mFreezingScreen, mVisibleRequested,
                 new RuntimeException().fillInStackTrace());
-        if (!hiddenRequested) {
+        if (mVisibleRequested) {
             if (!mFreezingScreen) {
                 mFreezingScreen = true;
                 mWmService.registerAppFreezeListener(this);
@@ -4939,8 +4941,8 @@
                 return;
             }
             ProtoLog.v(WM_DEBUG_ORIENTATION,
-                        "Clear freezing of %s: hidden=%b freezing=%b", appToken,
-                                isHidden(), isFreezingScreen());
+                        "Clear freezing of %s: visible=%b freezing=%b", appToken,
+                                isVisible(), isFreezingScreen());
             stopFreezingScreen(true, force);
         }
     }
@@ -5100,7 +5102,7 @@
         boolean nowGone = mReportedVisibilityResults.nowGone;
 
         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
-        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden();
+        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible();
         if (!nowGone) {
             // If the app is not yet gone, then it can only become visible/drawn.
             if (!nowDrawn) {
@@ -5182,7 +5184,7 @@
                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
                             + " pv=" + w.isVisibleByPolicy()
                             + " mDrawState=" + winAnimator.drawStateToString()
-                            + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
+                            + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested
                             + " a=" + isAnimating(TRANSITION));
                 }
             }
@@ -5290,7 +5292,7 @@
      * currently pausing, or is resumed.
      */
     public boolean isInterestingToUserLocked() {
-        return visible || nowVisible || mState == PAUSING || mState == RESUMED;
+        return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
     }
 
     void setSleeping(boolean _sleeping) {
@@ -5364,7 +5366,7 @@
             // We're not ready for this kind of thing.
             return false;
         }
-        if (visible) {
+        if (mVisibleRequested) {
             // The user would notice this!
             return false;
         }
@@ -5461,11 +5463,11 @@
             // well there is no point now.
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData");
             mStartingData = null;
-            if (mHiddenSetFromTransferredStartingWindow) {
-                // We set the hidden state to false for the token from a transferred starting window.
-                // We now reset it back to true since the starting window was the last window in the
-                // token.
-                setHidden(true);
+            if (mVisibleSetFromTransferredStartingWindow) {
+                // We set the visible state to true for the token from a transferred starting
+                // window. We now reset it back to false since the starting window was the last
+                // window in the token.
+                setVisible(false);
             }
         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
             // If this is the last window except for a starting transition window,
@@ -5803,7 +5805,7 @@
 
     @Override
     void prepareSurfaces() {
-        final boolean show = !isHidden() || isAnimating();
+        final boolean show = isVisible() || isAnimating();
 
         if (mSurfaceControl != null) {
             if (show && !mLastSurfaceShowing) {
@@ -5922,7 +5924,7 @@
                 "AppWindowToken");
 
         clearThumbnail();
-        setClientHidden(isHidden() && hiddenRequested);
+        setClientHidden(!isVisible() && !mVisibleRequested);
 
         getDisplayContent().computeImeTargetIfNeeded(this);
 
@@ -6519,7 +6521,7 @@
         if (display == null) {
             return;
         }
-        if (visible) {
+        if (mVisibleRequested) {
             // It may toggle the UI for user to restart the size compatibility mode activity.
             display.handleActivitySizeCompatModeIfNeeded(this);
         } else if (mCompatDisplayInsets != null) {
@@ -6816,7 +6818,7 @@
             } else {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is relaunching " + this);
-                if (DEBUG_STATES && !visible) {
+                if (DEBUG_STATES && !mVisibleRequested) {
                     Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
                             + " called by " + Debug.getCallers(4));
                 }
@@ -7002,7 +7004,7 @@
         // Reset the existing override configuration so it can be updated according to the latest
         // configuration.
         clearSizeCompatMode();
-        if (visible) {
+        if (mVisibleRequested) {
             // Configuration will be ensured when becoming visible, so if it is already visible,
             // then the manual update is needed.
             updateSizeCompatMode();
@@ -7015,7 +7017,7 @@
         // The restarting state avoids removing this record when process is died.
         setState(RESTARTING_PROCESS, "restartActivityProcess");
 
-        if (!visible || mHaveState) {
+        if (!mVisibleRequested || mHaveState) {
             // Kill its process immediately because the activity should be in background.
             // The activity state will be update to {@link #DESTROYED} in
             // {@link ActivityStack#cleanUp} when handling process died.
@@ -7306,12 +7308,13 @@
         writeToProto(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL);
         writeIdentifierToProto(proto, IDENTIFIER);
         proto.write(STATE, mState.toString());
-        proto.write(VISIBLE, visible);
+        proto.write(VISIBLE_REQUESTED, mVisibleRequested);
         proto.write(FRONT_OF_TASK, isRootOfTask());
         if (hasProcess()) {
             proto.write(PROC_ID, app.getPid());
         }
         proto.write(TRANSLUCENT, !occludesParent());
+        proto.write(VISIBLE, mVisible);
     }
 
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
@@ -7342,7 +7345,7 @@
         }
         proto.write(FILLS_PARENT, mOccludesParent);
         proto.write(APP_STOPPED, mAppStopped);
-        proto.write(HIDDEN_REQUESTED, hiddenRequested);
+        proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE_REQUESTED, mVisibleRequested);
         proto.write(CLIENT_HIDDEN, mClientHidden);
         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
         proto.write(REPORTED_DRAWN, reportedDrawn);
@@ -7357,11 +7360,12 @@
         }
         proto.write(STARTING_DISPLAYED, startingDisplayed);
         proto.write(STARTING_MOVED, startingMoved);
-        proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW,
-                mHiddenSetFromTransferredStartingWindow);
+        proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
+                mVisibleSetFromTransferredStartingWindow);
         for (Rect bounds : mFrozenBounds) {
             bounds.writeToProto(proto, FROZEN_BOUNDS);
         }
+        proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE, mVisible);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index c56a9e2..6e75f9c 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -73,7 +73,7 @@
 
     public boolean isActivityVisible() {
         synchronized (mService.mGlobalLock) {
-            return mActivity.visible || mActivity.isState(RESUMED, PAUSING);
+            return mActivity.mVisibleRequested || mActivity.isState(RESUMED, PAUSING);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 8d90d6d..cc9cd70 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -297,7 +297,7 @@
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
      */
-    private final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
+    private final ArrayList<ActivityRecord> mLruActivities = new ArrayList<>();
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -1060,14 +1060,15 @@
     }
 
     /** @return {@code true} if LRU list contained the specified activity. */
-    final boolean removeActivityFromLRUList(ActivityRecord activity) {
-        return mLRUActivities.remove(activity);
+    final boolean inLruList(ActivityRecord activity) {
+        return mLruActivities.contains(activity);
     }
 
-    final boolean updateLRUListLocked(ActivityRecord r) {
-        final boolean hadit = mLRUActivities.remove(r);
-        mLRUActivities.add(r);
-        return hadit;
+    /** @return {@code true} if the given activity was contained in LRU list. */
+    final boolean updateLruList(ActivityRecord r) {
+        final boolean contained = mLruActivities.remove(r);
+        mLruActivities.add(r);
+        return contained;
     }
 
     final boolean isHomeOrRecentsStack() {
@@ -1628,7 +1629,8 @@
                 prev = prev.completeFinishing("completePausedLocked");
             } else if (prev.hasProcess()) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
-                        + " wasStopping=" + wasStopping + " visible=" + prev.visible);
+                        + " wasStopping=" + wasStopping
+                        + " visibleRequested=" + prev.mVisibleRequested);
                 if (prev.deferRelaunchUntilPaused) {
                     // Complete the deferred relaunch that was waiting for pause to complete.
                     if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
@@ -1638,7 +1640,7 @@
                     // We can't clobber it, because the stop confirmation will not be handled.
                     // We don't need to schedule another stop, we only need to let it happen.
                     prev.setState(STOPPING, "completePausedLocked");
-                } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
+                } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) {
                     // Clear out any deferred client hide we might currently have.
                     prev.setDeferHidingClient(false);
                     // If we were visible then resumeTopActivities will release resources before
@@ -1759,7 +1761,7 @@
 
     boolean isTopActivityVisible() {
         final ActivityRecord topActivity = getTopActivity();
-        return topActivity != null && topActivity.visible;
+        return topActivity != null && topActivity.mVisibleRequested;
     }
 
     /**
@@ -1900,7 +1902,7 @@
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = getChildAt(taskNdx);
             ActivityRecord r = task.topRunningActivityLocked();
-            if (r == null || r.finishing || !r.visible) {
+            if (r == null || r.finishing || !r.mVisibleRequested) {
                 task.mLayerRank = -1;
             } else {
                 task.mLayerRank = baseLayer + layer++;
@@ -1989,7 +1991,7 @@
                         if (!r.attachedToProcess()) {
                             makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
                                     resumeTopActivity && isTop, r);
-                        } else if (r.visible) {
+                        } else if (r.mVisibleRequested) {
                             // If this activity is already visible, then there is nothing to do here.
                             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                     "Skipping: already visible at " + r);
@@ -2166,16 +2168,16 @@
         // invisible. If the app is already visible, it must have died while it was visible. In this
         // case, we'll show the dead window but will not restart the app. Otherwise we could end up
         // thrashing.
-        if (isTop || !r.visible) {
+        if (isTop || !r.mVisibleRequested) {
             // This activity needs to be visible, but isn't even running...
             // get it started and resume if no other stack in this stack is resumed.
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
             if (r != starting) {
                 r.startFreezingScreenLocked(configChanges);
             }
-            if (!r.visible || r.mLaunchTaskBehind) {
+            if (!r.mVisibleRequested || r.mLaunchTaskBehind) {
                 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
-                r.setVisible(true);
+                r.setVisibility(true);
             }
             if (r != starting) {
                 mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
@@ -2618,7 +2620,8 @@
 
         if (next.attachedToProcess()) {
             if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
-                    + " stopped=" + next.stopped + " visible=" + next.visible);
+                    + " stopped=" + next.stopped
+                    + " visibleRequested=" + next.mVisibleRequested);
 
             // If the previous activity is translucent, force a visibility update of
             // the next activity, so that it's added to WM's opening app list, and
@@ -2633,7 +2636,7 @@
                     && !lastFocusedStack.mLastPausedActivity.occludesParent()));
 
             // This activity is now becoming visible.
-            if (!next.visible || next.stopped || lastActivityTranslucent) {
+            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
                 next.setVisibility(true);
             }
 
@@ -2653,7 +2656,7 @@
 
             next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
                     true /* activityChange */, true /* updateOomAdj */);
-            updateLRUListLocked(next);
+            updateLruList(next);
 
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
@@ -2688,7 +2691,7 @@
                     // Do over!
                     mStackSupervisor.scheduleResumeTopActivities();
                 }
-                if (!next.visible || next.stopped) {
+                if (!next.mVisibleRequested || next.stopped) {
                     next.setVisibility(true);
                 }
                 next.completeResumeLocked();
@@ -3357,7 +3360,7 @@
 
         final ActivityRecord top = stack.topRunningActivityLocked();
 
-        if (stack.isActivityTypeHome() && (top == null || !top.visible)) {
+        if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
             // If we will be focusing on the home stack next and its current top activity isn't
             // visible, then use the move the home stack task to top to make the activity visible.
             stack.getDisplay().moveHomeActivityToTop(reason);
@@ -3643,10 +3646,10 @@
      * an activity moves away from the stack.
      */
     void onActivityRemovedFromStack(ActivityRecord r) {
-        removeActivityFromLRUList(r);
         removeTimeoutsForActivity(r);
 
         mExitingActivities.remove(r);
+        mLruActivities.remove(r);
 
         if (mResumedActivity != null && mResumedActivity == r) {
             setResumedActivity(null, "onActivityRemovedFromStack");
@@ -3657,9 +3660,12 @@
     }
 
     void onActivityAddedToStack(ActivityRecord r) {
-        if(r.getState() == RESUMED) {
+        if (r.isState(RESUMED)) {
             setResumedActivity(r, "onActivityAddedToStack");
         }
+        if (r.hasProcess()) {
+            updateLruList(r);
+        }
     }
 
     /// HANDLER INTERFACE BEGIN
@@ -3817,7 +3823,7 @@
     }
 
     private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
-        removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
+        removeHistoryRecordsForAppLocked(mLruActivities, app, "mLruActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
                 "mStoppingActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
@@ -3851,7 +3857,7 @@
                         "Record #" + targetIndex + " " + r + ": app=" + r.app);
 
                 if (r.app == app) {
-                    if (r.visible) {
+                    if (r.mVisibleRequested) {
                         hasVisibleActivities = true;
                     }
                     final boolean remove;
@@ -3867,8 +3873,8 @@
                         // Don't currently have state for the activity, or
                         // it is finishing -- always remove it.
                         remove = true;
-                    } else if (!r.visible && r.launchCount > 2 &&
-                            r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+                    } else if (!r.mVisibleRequested && r.launchCount > 2
+                            && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
                         // We have launched this activity too many times since it was
                         // able to run, so give up and remove it.
                         // (Note if the activity is visible, we don't remove the record.
@@ -3904,7 +3910,7 @@
                         // it died, we leave the dead window on screen so it's basically visible.
                         // This is needed when user later tap on the dead window, we need to stop
                         // other apps when user transfers focus to the restarted activity.
-                        r.nowVisible = r.visible;
+                        r.nowVisible = r.mVisibleRequested;
                     }
                     r.cleanUp(true /* cleanServices */, true /* setState */);
                     if (remove) {
@@ -4086,7 +4092,7 @@
      * Ensures all visible activities at or below the input activity have the right configuration.
      */
     void ensureVisibleActivitiesConfigurationLocked(ActivityRecord start, boolean preserveWindow) {
-        if (start == null || !start.visible) {
+        if (start == null || !start.mVisibleRequested) {
             return;
         }
 
@@ -4381,7 +4387,7 @@
         boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
                 needSep);
 
-        printed |= dumpHistoryList(fd, pw, mLRUActivities, "    ", "Run", false,
+        printed |= dumpHistoryList(fd, pw, mLruActivities, "    ", "Run", false,
                 !dumpAll, false, dumpPackage, true,
                 "    Running activities (most recent first):", null);
 
@@ -4481,7 +4487,7 @@
                 final ActivityRecord a = task.getChildAt(activityNdx);
                 if (a.info.packageName.equals(packageName)) {
                     a.forceNewConfig = true;
-                    if (starting != null && a == starting && a.visible) {
+                    if (starting != null && a == starting && a.mVisibleRequested) {
                         a.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
                     }
                 }
@@ -4658,7 +4664,7 @@
         // Apps may depend on onResume()/onPause() being called in pairs.
         if (setResume) {
             r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded");
-            updateLRUListLocked(r);
+            updateLruList(r);
         }
         // If the activity was previously pausing, then ensure we transfer that as well
         if (setPause) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 79fae06..4828a8d 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -773,12 +773,11 @@
             }
 
             if (r.getActivityStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
-                    true /* isTop */)) {
-                // We only set the visibility to true if the activity is allowed to be visible
-                // based on
-                // keyguard state. This avoids setting this into motion in window manager that is
-                // later cancelled due to later calls to ensure visible activities that set
-                // visibility back to false.
+                    true /* isTop */) && r.allowMoveToFront()) {
+                // We only set the visibility to true if the activity is not being launched in
+                // background, and is allowed to be visible based on keyguard state. This avoids
+                // setting this into motion in window manager that is later cancelled due to later
+                // calls to ensure visible activities that set visibility back to false.
                 r.setVisibility(true);
             }
 
@@ -913,7 +912,7 @@
         }
 
         r.launchFailed = false;
-        if (stack.updateLRUListLocked(r)) {
+        if (stack.updateLruList(r)) {
             Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 3c79c32..d3fd450 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -182,9 +182,17 @@
 
         final ActivityDisplay display =
                 mService.mRootActivityContainer.getActivityDisplay(displayId);
-        // Make sure home stack exist on display.
-        final ActivityStack homeStack =
-                display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+        // The home activity will be started later, defer resuming to avoid unneccerary operations
+        // (e.g. start home recursively) when creating home stack.
+        mSupervisor.beginDeferResume();
+        final ActivityStack homeStack;
+        try {
+            // Make sure home stack exist on display.
+            homeStack = display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
+                    ON_TOP);
+        } finally {
+            mSupervisor.endDeferResume();
+        }
 
         mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
                 .setOutActivity(tmpOutRecord)
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index bef6af3..ff1b423 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -688,15 +688,16 @@
      * compare z-order.
      *
      * @param apps The list of apps to search.
-     * @param ignoreHidden If set to true, ignores apps that are {@link ActivityRecord#isHidden}.
+     * @param ignoreInvisible If set to true, ignores apps that are not
+     *                        {@link ActivityRecord#isVisible}.
      * @return The top {@link ActivityRecord}.
      */
-    private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreHidden) {
+    private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) {
         int topPrefixOrderIndex = Integer.MIN_VALUE;
         ActivityRecord topApp = null;
         for (int i = apps.size() - 1; i >= 0; i--) {
             final ActivityRecord app = apps.valueAt(i);
-            if (ignoreHidden && app.isHidden()) {
+            if (ignoreInvisible && !app.isVisible()) {
                 continue;
             }
             final int prefixOrderIndex = app.getPrefixOrderIndex();
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
deleted file mode 100644
index b73b481..0000000
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
-import android.view.SurfaceControl;
-
-import java.util.function.Supplier;
-
-class CircularDisplayMask {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "CircularDisplayMask" : TAG_WM;
-
-    // size of the chin
-    private int mScreenOffset = 0;
-    // Display dimensions
-    private Point mScreenSize;
-
-    private final SurfaceControl mSurfaceControl;
-    private final Surface mSurface;
-    private int mLastDW;
-    private int mLastDH;
-    private boolean mDrawNeeded;
-    private Paint mPaint;
-    private int mRotation;
-    private boolean mVisible;
-    private boolean mDimensionsUnequal = false;
-    private int mMaskThickness;
-
-    CircularDisplayMask(Supplier<Surface> surfaceFactory, DisplayContent dc, int zOrder,
-            int screenOffset, int maskThickness, SurfaceControl.Transaction t) {
-        final Display display = dc.getDisplay();
-        mSurface = surfaceFactory.get();
-        mScreenSize = new Point();
-        display.getSize(mScreenSize);
-        if (mScreenSize.x != mScreenSize.y + screenOffset) {
-            Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() +
-                    "are not equal, circularMask will not be drawn.");
-            mDimensionsUnequal = true;
-        }
-
-        SurfaceControl ctrl = null;
-        try {
-            ctrl = dc.makeOverlay()
-                    .setName("CircularDisplayMask")
-                    .setBufferSize(mScreenSize.x, mScreenSize.y) // not a typo
-                    .setFormat(PixelFormat.TRANSLUCENT)
-                    .build();
-
-            t.setLayerStack(ctrl, display.getLayerStack());
-            t.setLayer(ctrl, zOrder);
-            t.setPosition(ctrl, 0, 0);
-            t.show(ctrl);
-            mSurface.copyFrom(ctrl);
-        } catch (OutOfResourcesException e) {
-        }
-        mSurfaceControl = ctrl;
-        mDrawNeeded = true;
-        mPaint = new Paint();
-        mPaint.setAntiAlias(true);
-        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-        mScreenOffset = screenOffset;
-        mMaskThickness = maskThickness;
-    }
-
-    private void drawIfNeeded(SurfaceControl.Transaction t) {
-        if (!mDrawNeeded || !mVisible || mDimensionsUnequal) {
-            return;
-        }
-        mDrawNeeded = false;
-
-        Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y);
-        Canvas c = null;
-        try {
-            c = mSurface.lockCanvas(dirty);
-        } catch (IllegalArgumentException e) {
-        } catch (Surface.OutOfResourcesException e) {
-        }
-        if (c == null) {
-            return;
-        }
-        switch (mRotation) {
-            case Surface.ROTATION_0:
-            case Surface.ROTATION_90:
-                // chin bottom or right
-                t.setPosition(mSurfaceControl, 0, 0);
-                break;
-            case Surface.ROTATION_180:
-                // chin top
-                t.setPosition(mSurfaceControl, 0, -mScreenOffset);
-                break;
-            case Surface.ROTATION_270:
-                // chin left
-                t.setPosition(mSurfaceControl, -mScreenOffset, 0);
-                break;
-        }
-
-        int circleRadius = mScreenSize.x / 2;
-        c.drawColor(Color.BLACK);
-
-        // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the
-        // display edges.
-        c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint);
-        mSurface.unlockCanvasAndPost(c);
-    }
-
-    // Note: caller responsible for being inside
-    // Surface.openTransaction() / closeTransaction()
-    public void setVisibility(boolean on, SurfaceControl.Transaction t) {
-        if (mSurfaceControl == null) {
-            return;
-        }
-        mVisible = on;
-        drawIfNeeded(t);
-        if (on) {
-            t.show(mSurfaceControl);
-        } else {
-            t.hide(mSurfaceControl);
-        }
-    }
-
-    void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) {
-        if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
-            return;
-        }
-        mLastDW = dw;
-        mLastDH = dh;
-        mDrawNeeded = true;
-        mRotation = rotation;
-        drawIfNeeded(t);
-    }
-
-}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7cca08f..e78e302 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -652,12 +652,12 @@
                     + " config reported=" + w.isLastConfigReportedToClient());
             final ActivityRecord activity = w.mActivityRecord;
             if (gone) Slog.v(TAG, "  GONE: mViewVisibility=" + w.mViewVisibility
-                    + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden()
-                    + " hiddenRequested=" + (activity != null && activity.hiddenRequested)
+                    + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
+                    + " visibleRequested=" + (activity != null && activity.mVisibleRequested)
                     + " parentHidden=" + w.isParentWindowHidden());
             else Slog.v(TAG, "  VIS: mViewVisibility=" + w.mViewVisibility
-                    + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden()
-                    + " hiddenRequested=" + (activity != null && activity.hiddenRequested)
+                    + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
+                    + " visibleRequested=" + (activity != null && activity.mVisibleRequested)
                     + " parentHidden=" + w.isParentWindowHidden());
         }
 
@@ -1173,6 +1173,9 @@
         if (!isReady() || mActivityDisplay == null) {
             return;
         }
+        if (mDisplayRotation.isWaitingForRemoteRotation()) {
+            return;
+        }
         final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked();
         if (configUpdated) {
             return;
@@ -2257,7 +2260,7 @@
      */
     boolean pointWithinAppWindow(int x, int y) {
         final int[] targetWindowType = {-1};
-        final Consumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
+        final PooledConsumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
             if (targetWindowType[0] != -1) {
                 return;
             }
@@ -2268,7 +2271,7 @@
             }
         }, PooledLambda.__(WindowState.class), mTmpRect);
         forAllWindows(fn, true /* traverseTopToBottom */);
-        ((PooledConsumer) fn).recycle();
+        fn.recycle();
         return FIRST_APPLICATION_WINDOW <= targetWindowType[0]
                         && targetWindowType[0] <= LAST_APPLICATION_WINDOW;
     }
@@ -2391,6 +2394,7 @@
             mWindowingLayer.release();
             mOverlayLayer.release();
             mInputMonitor.onDisplayRemoved();
+            mWmService.mDisplayNotificationController.dispatchDisplayRemoved(mActivityDisplay);
         } finally {
             mDisplayReady = false;
             mRemovingDisplay = false;
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index dc6b491..6b47c8a 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -39,20 +39,11 @@
     public final int mDisplayId;
 
     /**
-     * The current size of the screen; really; extends into the overscan area of the screen and
-     * doesn't account for any system elements like the status bar.
-     */
-    public final Rect mOverscan = new Rect();
-
-    /**
      * The current visible size of the screen; really; (ir)regardless of whether the status bar can
      * be hidden but not extending into the overscan area.
      */
     public final Rect mUnrestricted = new Rect();
 
-    /** Like mOverscan*, but allowed to move into the overscan region where appropriate. */
-    public final Rect mRestrictedOverscan = new Rect();
-
     /**
      * The current size of the screen; these may be different than (0,0)-(dw,dh) if the status bar
      * can't be hidden; in that case it effectively carves out that area of the display from all
@@ -109,8 +100,6 @@
      */
     public final Rect mDisplayCutoutSafe = new Rect();
 
-    private final Rect mDisplayInfoOverscan = new Rect();
-    private final Rect mRotatedDisplayInfoOverscan = new Rect();
     public int mDisplayWidth;
     public int mDisplayHeight;
 
@@ -125,43 +114,13 @@
         mDisplayWidth = info.logicalWidth;
         mDisplayHeight = info.logicalHeight;
         mRotation = info.rotation;
-        mDisplayInfoOverscan.set(
-                info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
         mDisplayInfoCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
     }
 
     public void onBeginLayout() {
-        switch (mRotation) {
-            case ROTATION_90:
-                mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
-                mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.right;
-                mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.bottom;
-                mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.left;
-                break;
-            case ROTATION_180:
-                mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.right;
-                mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.bottom;
-                mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.left;
-                mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.top;
-                break;
-            case ROTATION_270:
-                mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.bottom;
-                mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.left;
-                mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.top;
-                mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.right;
-                break;
-            default:
-                mRotatedDisplayInfoOverscan.set(mDisplayInfoOverscan);
-                break;
-        }
-
-        mRestrictedOverscan.set(0, 0, mDisplayWidth, mDisplayHeight);
-        mOverscan.set(mRestrictedOverscan);
-        mSystem.set(mRestrictedOverscan);
-        mUnrestricted.set(mRotatedDisplayInfoOverscan);
-        mUnrestricted.right = mDisplayWidth - mUnrestricted.right;
-        mUnrestricted.bottom = mDisplayHeight - mUnrestricted.bottom;
+        mUnrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
         mRestricted.set(mUnrestricted);
+        mSystem.set(mUnrestricted);
         mDock.set(mUnrestricted);
         mContent.set(mUnrestricted);
         mVoiceContent.set(mUnrestricted);
@@ -175,16 +134,16 @@
         if (!mDisplayCutout.getDisplayCutout().isEmpty()) {
             final DisplayCutout c = mDisplayCutout.getDisplayCutout();
             if (c.getSafeInsetLeft() > 0) {
-                mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
+                mDisplayCutoutSafe.left = mUnrestricted.left + c.getSafeInsetLeft();
             }
             if (c.getSafeInsetTop() > 0) {
-                mDisplayCutoutSafe.top = mRestrictedOverscan.top + c.getSafeInsetTop();
+                mDisplayCutoutSafe.top = mUnrestricted.top + c.getSafeInsetTop();
             }
             if (c.getSafeInsetRight() > 0) {
-                mDisplayCutoutSafe.right = mRestrictedOverscan.right - c.getSafeInsetRight();
+                mDisplayCutoutSafe.right = mUnrestricted.right - c.getSafeInsetRight();
             }
             if (c.getSafeInsetBottom() > 0) {
-                mDisplayCutoutSafe.bottom = mRestrictedOverscan.bottom - c.getSafeInsetBottom();
+                mDisplayCutoutSafe.bottom = mUnrestricted.bottom - c.getSafeInsetBottom();
             }
         }
     }
@@ -210,12 +169,8 @@
         dumpFrame(mSystem, "mSystem", myPrefix, pw);
         dumpFrame(mContent, "mContent", myPrefix, pw);
         dumpFrame(mVoiceContent, "mVoiceContent", myPrefix, pw);
-        dumpFrame(mOverscan, "mOverscan", myPrefix, pw);
-        dumpFrame(mRestrictedOverscan, "mRestrictedOverscan", myPrefix, pw);
         dumpFrame(mRestricted, "mRestricted", myPrefix, pw);
         dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
-        dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
-        dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
         pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6a6b2517..f8c1ad9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -163,7 +163,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.util.function.TriConsumer;
 import com.android.internal.view.AppearanceRegion;
@@ -294,9 +293,6 @@
 
     private boolean mIsFreeformWindowOverlappingWithNavBar;
 
-    /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
-    @Px private int mWindowOutsetBottom;
-
     private final StatusBarController mStatusBarController;
 
     private final BarController mNavigationBarController;
@@ -1209,7 +1205,6 @@
      * @param outContentInsets The areas covered by system windows, expressed as positive insets.
      * @param outStableInsets The areas covered by stable system windows irrespective of their
      *                        current visibility. Expressed as positive insets.
-     * @param outOutsets The areas that are not real display, but we would like to treat as such.
      * @param outDisplayCutout The area that has been cut away from the display.
      * @return Whether to always consume the system bars.
      *         See {@link #areSystemBarsForcedShownLw(WindowState)}.
@@ -1217,28 +1212,11 @@
     public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
             DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
             Rect outContentInsets, Rect outStableInsets,
-            Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
+            DisplayCutout.ParcelableWrapper outDisplayCutout) {
         final int fl = PolicyControl.getWindowFlags(null, attrs);
         final int pfl = attrs.privateFlags;
         final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
         final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
-        final int displayRotation = displayFrames.mRotation;
-
-        final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
-        if (useOutsets) {
-            int outset = mWindowOutsetBottom;
-            if (outset > 0) {
-                if (displayRotation == Surface.ROTATION_0) {
-                    outOutsets.bottom += outset;
-                } else if (displayRotation == Surface.ROTATION_90) {
-                    outOutsets.right += outset;
-                } else if (displayRotation == Surface.ROTATION_180) {
-                    outOutsets.top += outset;
-                } else if (displayRotation == Surface.ROTATION_270) {
-                    outOutsets.left += outset;
-                }
-            }
-        }
 
         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
         final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -1268,8 +1246,8 @@
                 } else {
                     cf = displayFrames.mStable;
                 }
-            } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
-                cf = displayFrames.mOverscan;
+            } else if ((fl & FLAG_FULLSCREEN) != 0) {
+                cf = displayFrames.mUnrestricted;
             } else {
                 cf = displayFrames.mCurrent;
             }
@@ -1312,11 +1290,6 @@
         return impliedFlags;
     }
 
-    private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
-        return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
-    }
-
     private final Runnable mClearHideNavigationFlag = new Runnable() {
         @Override
         public void run() {
@@ -1482,11 +1455,9 @@
 
             w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
                     displayFrames.mUnrestricted /* displayFrame */,
-                    displayFrames.mUnrestricted /* overscanFrame */,
                     displayFrames.mUnrestricted /* contentFrame */,
                     displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
-                    displayFrames.mUnrestricted /* stableFrame */,
-                    displayFrames.mUnrestricted /* outsetFrame */);
+                    displayFrames.mUnrestricted /* stableFrame */);
             w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
             w.computeFrameLw();
             final Rect frame = w.getFrameLw();
@@ -1530,7 +1501,6 @@
         displayFrames.mVoiceContent.set(dockFrame);
         displayFrames.mSystem.set(dockFrame);
         displayFrames.mContent.set(dockFrame);
-        displayFrames.mRestrictedOverscan.set(dockFrame);
     }
 
     private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
@@ -1544,9 +1514,9 @@
         final WindowFrames windowFrames = mStatusBar.getWindowFrames();
         windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
                 displayFrames.mUnrestricted /* displayFrame */,
-                displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
+                displayFrames.mStable /* contentFrame */,
                 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
-                displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
+                displayFrames.mStable /* stableFrame */);
         windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
 
         // Let the status bar determine its size.
@@ -1630,8 +1600,7 @@
                 mNavigationBarController.setBarShowingLw(true);
             } else if (navVisible) {
                 mNavigationBarController.setBarShowingLw(true);
-                dockFrame.bottom = displayFrames.mRestricted.bottom =
-                        displayFrames.mRestrictedOverscan.bottom = top;
+                dockFrame.bottom = displayFrames.mRestricted.bottom = top;
             } else {
                 // We currently want to hide the navigation UI - unless we expanded the status bar.
                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1653,8 +1622,7 @@
                 mNavigationBarController.setBarShowingLw(true);
             } else if (navVisible) {
                 mNavigationBarController.setBarShowingLw(true);
-                dockFrame.right = displayFrames.mRestricted.right =
-                        displayFrames.mRestrictedOverscan.right = left;
+                dockFrame.right = displayFrames.mRestricted.right = left;
             } else {
                 // We currently want to hide the navigation UI - unless we expanded the status bar.
                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1676,8 +1644,7 @@
                 mNavigationBarController.setBarShowingLw(true);
             } else if (navVisible) {
                 mNavigationBarController.setBarShowingLw(true);
-                dockFrame.left = displayFrames.mRestricted.left =
-                        displayFrames.mRestrictedOverscan.left = right;
+                dockFrame.left = displayFrames.mRestricted.left = right;
             } else {
                 // We currently want to hide the navigation UI - unless we expanded the status bar.
                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1699,11 +1666,10 @@
         // And compute the final frame.
         sTmpRect.setEmpty();
         mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
-                navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
+                navigationFrame /* displayFrame */,
                 displayFrames.mDisplayCutoutSafe /* contentFrame */,
                 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
-                navigationFrame /* stableFrame */,
-                displayFrames.mDisplayCutoutSafe /* outsetFrame */);
+                navigationFrame /* stableFrame */);
         mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
         mNavigationBar.computeFrameLw();
         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
@@ -1713,7 +1679,7 @@
     }
 
     private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
-            boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
+            boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
             DisplayFrames displayFrames) {
         if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
             // Here's a special case: if the child window is not the 'dock window'
@@ -1725,29 +1691,25 @@
             // compute the frames that would be appropriate without the dock.
             vf.set(displayFrames.mDock);
             cf.set(displayFrames.mDock);
-            of.set(displayFrames.mDock);
             df.set(displayFrames.mDock);
         } else {
 
-            // In case we forced the window to draw behind the navigation bar, restrict df/of to
-            // DF.RestrictedOverscan to simulate old compat behavior.
+            // In case we forced the window to draw behind the navigation bar, restrict df to
+            // DF.Restricted to simulate old compat behavior.
             Rect parentDisplayFrame = attached.getDisplayFrameLw();
-            Rect parentOverscan = attached.getOverscanFrameLw();
             final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
             if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
                     && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
                     && (attachedAttrs.systemUiVisibility
                             & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
-                parentOverscan = new Rect(parentOverscan);
-                parentOverscan.intersect(displayFrames.mRestrictedOverscan);
                 parentDisplayFrame = new Rect(parentDisplayFrame);
-                parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
+                parentDisplayFrame.intersect(displayFrames.mRestricted);
             }
 
             // The effective display frame of the attached window depends on whether it is taking
             // care of insetting its content. If not, we need to use the parent's content frame so
             // that the entire window is positioned within that content. Otherwise we can use the
-            // overscan frame and let the attached window take care of positioning its content
+            // parent display frame and let the attached window take care of positioning its content
             // appropriately.
             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                 // Set the content frame of the attached window to the parent's decor frame
@@ -1755,7 +1717,7 @@
                 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
                 // Otherwise, use the overscan frame.
                 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
-                        ? attached.getContentFrameLw() : parentOverscan);
+                        ? attached.getContentFrameLw() : parentDisplayFrame);
             } else {
                 // If the window is resizing, then we want to base the content frame on our attached
                 // content frame to resize...however, things can be tricky if the attached window is
@@ -1770,7 +1732,6 @@
                 }
             }
             df.set(insetDecors ? parentDisplayFrame : cf);
-            of.set(insetDecors ? parentOverscan : cf);
             vf.set(attached.getVisibleFrameLw());
         }
         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
@@ -1820,7 +1781,6 @@
             return;
         }
         final WindowManager.LayoutParams attrs = win.getAttrs();
-        final boolean isDefaultDisplay = win.isDefaultDisplay();
 
         final int type = attrs.type;
         final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -1831,11 +1791,9 @@
 
         final WindowFrames windowFrames = win.getWindowFrames();
 
-        windowFrames.setHasOutsets(false);
         sTmpLastParentFrame.set(windowFrames.mParentFrame);
         final Rect pf = windowFrames.mParentFrame;
         final Rect df = windowFrames.mDisplayFrame;
-        final Rect of = windowFrames.mOverscanFrame;
         final Rect cf = windowFrames.mContentFrame;
         final Rect vf = windowFrames.mVisibleFrame;
         final Rect dcf = windowFrames.mDecorFrame;
@@ -1860,21 +1818,20 @@
         if (type == TYPE_INPUT_METHOD) {
             vf.set(displayFrames.mDock);
             cf.set(displayFrames.mDock);
-            of.set(displayFrames.mDock);
             df.set(displayFrames.mDock);
             windowFrames.mParentFrame.set(displayFrames.mDock);
             // IM dock windows layout below the nav bar...
-            pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
+            pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
             // ...with content insets above the nav bar
             cf.bottom = vf.bottom = displayFrames.mStable.bottom;
             if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
                 // The status bar forces the navigation bar while it's visible. Make sure the IME
                 // avoids the navigation bar in that case.
                 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
-                    pf.right = df.right = of.right = cf.right = vf.right =
+                    pf.right = df.right = cf.right = vf.right =
                             displayFrames.mStable.right;
                 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
-                    pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
+                    pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
                 }
             }
 
@@ -1897,7 +1854,6 @@
             // IM dock windows always go to the bottom of the screen.
             attrs.gravity = Gravity.BOTTOM;
         } else if (type == TYPE_VOICE_INTERACTION) {
-            of.set(displayFrames.mUnrestricted);
             df.set(displayFrames.mUnrestricted);
             pf.set(displayFrames.mUnrestricted);
             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
@@ -1911,9 +1867,8 @@
                 vf.set(cf);
             }
         } else if (type == TYPE_WALLPAPER) {
-            layoutWallpaper(displayFrames, pf, df, of, cf);
+            layoutWallpaper(displayFrames, pf, df, cf);
         } else if (win == mStatusBar) {
-            of.set(displayFrames.mUnrestricted);
             df.set(displayFrames.mUnrestricted);
             pf.set(displayFrames.mUnrestricted);
             cf.set(displayFrames.mStable);
@@ -1967,7 +1922,7 @@
                 if (attached != null) {
                     // If this window is attached to another, our display
                     // frame is the same as the one we are attached to.
-                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
+                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
                             displayFrames);
                 } else {
                     if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
@@ -1977,24 +1932,17 @@
                         //
                         // However, they should still dodge the navigation bar if it exists.
 
-                        pf.left = df.left = of.left = hasNavBar
+                        pf.left = df.left = hasNavBar
                                 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
-                        pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
-                        pf.right = df.right = of.right = hasNavBar
+                        pf.top = df.top = displayFrames.mUnrestricted.top;
+                        pf.right = df.right = hasNavBar
                                 ? displayFrames.mRestricted.right
                                 : displayFrames.mUnrestricted.right;
-                        pf.bottom = df.bottom = of.bottom = hasNavBar
+                        pf.bottom = df.bottom = hasNavBar
                                 ? displayFrames.mRestricted.bottom
                                 : displayFrames.mUnrestricted.bottom;
 
                         if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
-                    } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
-                            && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
-                        // Asking to layout into the overscan region, so give it that pure
-                        // unrestricted area.
-                        of.set(displayFrames.mOverscan);
-                        df.set(displayFrames.mOverscan);
-                        pf.set(displayFrames.mOverscan);
                     } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                             && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
                             || type == TYPE_VOLUME_OVERLAY
@@ -2003,19 +1951,11 @@
                         // extend into the unrestricted overscan screen area. We only do this for
                         // application windows and certain system windows to ensure no window that
                         // can be above the nav bar can do this.
-                        df.set(displayFrames.mOverscan);
-                        pf.set(displayFrames.mOverscan);
-                        // We need to tell the app about where the frame inside the overscan is, so
-                        // it can inset its content by that amount -- it didn't ask to actually
-                        // extend itself into the overscan region.
-                        of.set(displayFrames.mUnrestricted);
+                        df.set(displayFrames.mUnrestricted);
+                        pf.set(displayFrames.mUnrestricted);
                     } else {
-                        df.set(displayFrames.mRestrictedOverscan);
-                        pf.set(displayFrames.mRestrictedOverscan);
-                        // We need to tell the app about where the frame inside the overscan
-                        // is, so it can inset its content by that amount -- it didn't ask
-                        // to actually extend itself into the overscan region.
-                        of.set(displayFrames.mUnrestricted);
+                        df.set(displayFrames.mRestricted);
+                        pf.set(displayFrames.mRestricted);
                     }
 
                     if ((fl & FLAG_FULLSCREEN) == 0) {
@@ -2053,19 +1993,17 @@
                 // gets everything, period.
                 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
                     cf.set(displayFrames.mUnrestricted);
-                    of.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
                     if (hasNavBar) {
-                        pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
-                        pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
-                        pf.bottom = df.bottom = of.bottom = cf.bottom =
+                        pf.left = df.left = cf.left = displayFrames.mDock.left;
+                        pf.right = df.right = cf.right = displayFrames.mRestricted.right;
+                        pf.bottom = df.bottom = cf.bottom =
                                 displayFrames.mRestricted.bottom;
                     }
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
                 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
                     // The navigation bar has Real Ultimate Power.
-                    of.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
@@ -2073,24 +2011,14 @@
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
                     // Fullscreen secure system overlays get what they ask for. Screenshot region
                     // selection overlay should also expand to full screen.
-                    cf.set(displayFrames.mOverscan);
-                    of.set(displayFrames.mOverscan);
-                    df.set(displayFrames.mOverscan);
-                    pf.set(displayFrames.mOverscan);
+                    cf.set(displayFrames.mUnrestricted);
+                    df.set(displayFrames.mUnrestricted);
+                    pf.set(displayFrames.mUnrestricted);
                 } else if (type == TYPE_BOOT_PROGRESS) {
                     // Boot progress screen always covers entire display.
-                    cf.set(displayFrames.mOverscan);
-                    of.set(displayFrames.mOverscan);
-                    df.set(displayFrames.mOverscan);
-                    pf.set(displayFrames.mOverscan);
-                } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
-                        && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
-                    // Asking to layout into the overscan region, so give it that pure unrestricted
-                    // area.
-                    cf.set(displayFrames.mOverscan);
-                    of.set(displayFrames.mOverscan);
-                    df.set(displayFrames.mOverscan);
-                    pf.set(displayFrames.mOverscan);
+                    cf.set(displayFrames.mUnrestricted);
+                    df.set(displayFrames.mUnrestricted);
+                    pf.set(displayFrames.mUnrestricted);
                 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (type == TYPE_STATUS_BAR
                         || type == TYPE_TOAST
@@ -2105,11 +2033,9 @@
                     // ask for layout in only content.  We can't currently figure out
                     // what the screen would be if only laying out to hide the nav bar.
                     cf.set(displayFrames.mUnrestricted);
-                    of.set(displayFrames.mUnrestricted);
                     df.set(displayFrames.mUnrestricted);
                     pf.set(displayFrames.mUnrestricted);
                 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
-                    of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
 
@@ -2123,7 +2049,6 @@
                     }
                 } else {
                     cf.set(displayFrames.mRestricted);
-                    of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
                 }
@@ -2140,7 +2065,7 @@
                         + "): attached to " + attached);
                 // A child window should be placed inside of the same visible
                 // frame that its parent had.
-                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
+                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
                         displayFrames);
             } else {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
@@ -2152,28 +2077,23 @@
                     // top of the status bar. They are protected by the STATUS_BAR_SERVICE
                     // permission, so they have the same privileges as the status bar itself.
                     cf.set(displayFrames.mRestricted);
-                    of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
                 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
                     // These dialogs are stable to interim decor changes.
                     cf.set(displayFrames.mStable);
-                    of.set(displayFrames.mStable);
                     df.set(displayFrames.mStable);
                     pf.set(displayFrames.mStable);
                 } else {
                     pf.set(displayFrames.mContent);
                     if (win.isVoiceInteraction()) {
                         cf.set(displayFrames.mVoiceContent);
-                        of.set(displayFrames.mVoiceContent);
                         df.set(displayFrames.mVoiceContent);
                     } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                         cf.set(displayFrames.mDock);
-                        of.set(displayFrames.mDock);
                         df.set(displayFrames.mDock);
                     } else {
                         cf.set(displayFrames.mContent);
-                        of.set(displayFrames.mContent);
                         df.set(displayFrames.mContent);
                     }
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
@@ -2252,34 +2172,8 @@
             df.left = df.top = -10000;
             df.right = df.bottom = 10000;
             if (type != TYPE_WALLPAPER) {
-                of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
-                of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
-            }
-        }
-
-        // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
-        // need to provide information to the clients that want to pretend that you can draw there.
-        // We only want to apply outsets to certain types of windows. For example, we never want to
-        // apply the outsets to floating dialogs, because they wouldn't make sense there.
-        final boolean useOutsets = shouldUseOutsets(attrs, fl);
-        if (isDefaultDisplay && useOutsets) {
-            final Rect osf = windowFrames.mOutsetFrame;
-            osf.set(cf.left, cf.top, cf.right, cf.bottom);
-            windowFrames.setHasOutsets(true);
-            int outset = mWindowOutsetBottom;
-            if (outset > 0) {
-                int rotation = displayFrames.mRotation;
-                if (rotation == Surface.ROTATION_0) {
-                    osf.bottom += outset;
-                } else if (rotation == Surface.ROTATION_90) {
-                    osf.right += outset;
-                } else if (rotation == Surface.ROTATION_180) {
-                    osf.top -= outset;
-                } else if (rotation == Surface.ROTATION_270) {
-                    osf.left -= outset;
-                }
-                if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
-                        + " with rotation " + rotation + ", result: " + osf);
+                cf.left = cf.top = vf.left = vf.top = -10000;
+                cf.right = cf.bottom = vf.right = vf.bottom = 10000;
             }
         }
 
@@ -2288,11 +2182,9 @@
                 + " attach=" + attached + " type=" + type
                 + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
-                + " of=" + of.toShortString()
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
                 + " dcf=" + dcf.toShortString()
-                + " sf=" + sf.toShortString()
-                + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
+                + " sf=" + sf.toShortString());
 
         if (!sTmpLastParentFrame.equals(pf)) {
             windowFrames.setContentChanged(true);
@@ -2311,12 +2203,11 @@
         }
     }
 
-    private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
-        // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
-        df.set(displayFrames.mOverscan);
-        pf.set(displayFrames.mOverscan);
+    private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
+        // The wallpaper has Real Ultimate Power
+        df.set(displayFrames.mUnrestricted);
+        pf.set(displayFrames.mUnrestricted);
         cf.set(displayFrames.mUnrestricted);
-        of.set(displayFrames.mUnrestricted);
     }
 
     private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
@@ -2722,7 +2613,6 @@
                         - getNavigationBarFrameHeight(portraitRotation, uiMode);
 
         updateConfigurationAndScreenSizeDependentBehaviors();
-        mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
     }
 
     void updateConfigurationAndScreenSizeDependentBehaviors() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 67f1d1b..0c68084 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -45,15 +45,19 @@
 import android.hardware.power.V1_0.PowerHint;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.IDisplayWindowRotationCallback;
 import android.view.Surface;
+import android.view.WindowContainerTransaction;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy;
@@ -212,6 +216,31 @@
     private boolean mDemoHdmiRotationLock;
     private boolean mDemoRotationLock;
 
+    private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
+
+    private boolean mIsWaitingForRemoteRotation = false;
+
+    private final Runnable mDisplayRotationHandlerTimeout =
+            new Runnable() {
+                @Override
+                public void run() {
+                    continueRotation(mRotation, null /* transaction */);
+                }
+            };
+
+    private final IDisplayWindowRotationCallback mRemoteRotationCallback =
+            new IDisplayWindowRotationCallback.Stub() {
+                @Override
+                public void continueRotateDisplay(int targetRotation,
+                        WindowContainerTransaction t) {
+                    synchronized (mService.getWindowManagerLock()) {
+                        mService.mH.sendMessage(PooledLambda.obtainMessage(
+                                DisplayRotation::continueRotation, DisplayRotation.this,
+                                targetRotation, t));
+                    }
+                }
+            };
+
     DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
         this(service, displayContent, displayContent.getDisplayPolicy(),
                 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
@@ -471,9 +500,52 @@
             prepareNormalRotationAnimation();
         }
 
+        // The display is frozen now, give a remote handler (system ui) some time to reposition
+        // things.
+        startRemoteRotation(oldRotation, mRotation);
+
         return true;
     }
 
+    /**
+     * A Remote rotation is when we are waiting for some registered (remote)
+     * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
+     *  to perform in sync with the rotation.
+     */
+    boolean isWaitingForRemoteRotation() {
+        return mIsWaitingForRemoteRotation;
+    }
+
+    private void startRemoteRotation(int fromRotation, int toRotation) {
+        if (mService.mDisplayRotationController == null) {
+            return;
+        }
+        mIsWaitingForRemoteRotation = true;
+        try {
+            mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
+                    fromRotation, toRotation, mRemoteRotationCallback);
+            mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
+            mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
+        } catch (RemoteException e) {
+            mIsWaitingForRemoteRotation = false;
+            return;
+        }
+    }
+
+    private void continueRotation(int targetRotation, WindowContainerTransaction t) {
+        synchronized (mService.mGlobalLock) {
+            if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
+                // Drop it, this is either coming from an outdated remote rotation; or, we've
+                // already moved on.
+                return;
+            }
+            mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
+            mIsWaitingForRemoteRotation = false;
+            mService.mAtmService.applyContainerTransaction(t);
+            mDisplayContent.sendNewConfiguration();
+        }
+    }
+
     void prepareNormalRotationAnimation() {
         final RotationAnimationPair anim = selectRotationAnimation();
         mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent);
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
new file mode 100644
index 0000000..dbc452f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -0,0 +1,75 @@
+/*
+ * 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.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.IDisplayWindowListener;
+
+/**
+ * Manages dispatch of relevant hierarchy changes to interested listeners. Listeners are assumed
+ * to be remote.
+ */
+class DisplayWindowListenerController {
+    RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>();
+
+//    private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>();
+    private final WindowManagerService mService;
+
+    DisplayWindowListenerController(WindowManagerService service) {
+        mService = service;
+    }
+
+    void registerListener(IDisplayWindowListener listener) {
+        synchronized (mService.mGlobalLock) {
+            mDisplayListeners.register(listener);
+            try {
+                for (int i = 0; i < mService.mAtmService.mRootActivityContainer.getChildCount();
+                        ++i) {
+                    ActivityDisplay d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
+                    listener.onDisplayAdded(d.mDisplayId);
+                }
+            } catch (RemoteException e) { }
+        }
+    }
+
+    void unregisterListener(IDisplayWindowListener listener) {
+        mDisplayListeners.unregister(listener);
+    }
+
+    void dispatchDisplayAdded(ActivityDisplay display) {
+        int count = mDisplayListeners.beginBroadcast();
+        for (int i = 0; i < count; ++i) {
+            try {
+                mDisplayListeners.getBroadcastItem(i).onDisplayAdded(display.mDisplayId);
+            } catch (RemoteException e) {
+            }
+        }
+        mDisplayListeners.finishBroadcast();
+    }
+
+    void dispatchDisplayRemoved(ActivityDisplay display) {
+        int count = mDisplayListeners.beginBroadcast();
+        for (int i = 0; i < count; ++i) {
+            try {
+                mDisplayListeners.getBroadcastItem(i).onDisplayRemoved(display.mDisplayId);
+            } catch (RemoteException e) {
+            }
+        }
+        mDisplayListeners.finishBroadcast();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 8507918..dac8b14 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -100,10 +100,6 @@
 
     private static class Entry {
         private final String mName;
-        private int mOverscanLeft;
-        private int mOverscanTop;
-        private int mOverscanRight;
-        private int mOverscanBottom;
         private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
         private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
         private int mUserRotation = Surface.ROTATION_0;
@@ -124,10 +120,6 @@
 
         private Entry(String name, Entry copyFrom) {
             this(name);
-            mOverscanLeft = copyFrom.mOverscanLeft;
-            mOverscanTop = copyFrom.mOverscanTop;
-            mOverscanRight = copyFrom.mOverscanRight;
-            mOverscanBottom = copyFrom.mOverscanBottom;
             mWindowingMode = copyFrom.mWindowingMode;
             mUserRotationMode = copyFrom.mUserRotationMode;
             mUserRotation = copyFrom.mUserRotation;
@@ -144,9 +136,7 @@
 
         /** @return {@code true} if all values are default. */
         private boolean isEmpty() {
-            return mOverscanLeft == 0 && mOverscanTop == 0 && mOverscanRight == 0
-                    && mOverscanBottom == 0
-                    && mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+            return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
                     && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
                     && mUserRotation == Surface.ROTATION_0
                     && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
@@ -202,15 +192,6 @@
         return newEntry;
     }
 
-    void setOverscanLocked(DisplayInfo displayInfo, int left, int top, int right, int bottom) {
-        final Entry entry = getOrCreateEntry(displayInfo);
-        entry.mOverscanLeft = left;
-        entry.mOverscanTop = top;
-        entry.mOverscanRight = right;
-        entry.mOverscanBottom = bottom;
-        writeSettingsIfNeeded(entry, displayInfo);
-    }
-
     void setUserRotation(DisplayContent displayContent, int rotationMode, int rotation) {
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final Entry entry = getOrCreateEntry(displayInfo);
@@ -405,11 +386,6 @@
         // Setting windowing mode first, because it may override overscan values later.
         dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId()));
 
-        displayInfo.overscanLeft = entry.mOverscanLeft;
-        displayInfo.overscanTop = entry.mOverscanTop;
-        displayInfo.overscanRight = entry.mOverscanRight;
-        displayInfo.overscanBottom = entry.mOverscanBottom;
-
         dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
                 entry.mUserRotation, entry.mFixedToUserRotation);
 
@@ -536,10 +512,6 @@
         String name = parser.getAttributeValue(null, "name");
         if (name != null) {
             Entry entry = new Entry(name);
-            entry.mOverscanLeft = getIntAttribute(parser, "overscanLeft");
-            entry.mOverscanTop = getIntAttribute(parser, "overscanTop");
-            entry.mOverscanRight = getIntAttribute(parser, "overscanRight");
-            entry.mOverscanBottom = getIntAttribute(parser, "overscanBottom");
             entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
                     WindowConfiguration.WINDOWING_MODE_UNDEFINED);
             entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
@@ -602,18 +574,6 @@
             for (Entry entry : mEntries.values()) {
                 out.startTag(null, "display");
                 out.attribute(null, "name", entry.mName);
-                if (entry.mOverscanLeft != 0) {
-                    out.attribute(null, "overscanLeft", Integer.toString(entry.mOverscanLeft));
-                }
-                if (entry.mOverscanTop != 0) {
-                    out.attribute(null, "overscanTop", Integer.toString(entry.mOverscanTop));
-                }
-                if (entry.mOverscanRight != 0) {
-                    out.attribute(null, "overscanRight", Integer.toString(entry.mOverscanRight));
-                }
-                if (entry.mOverscanBottom != 0) {
-                    out.attribute(null, "overscanBottom", Integer.toString(entry.mOverscanBottom));
-                }
                 if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
                     out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
                 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index caf95de..fc74d00 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -107,7 +107,7 @@
                 mTargetActivityType);
         ActivityRecord targetActivity = getTargetActivity(targetStack);
         if (targetActivity != null) {
-            if (targetActivity.visible || targetActivity.isTopRunningActivity()) {
+            if (targetActivity.mVisibleRequested || targetActivity.isTopRunningActivity()) {
                 // The activity is ready.
                 return;
             }
@@ -189,7 +189,7 @@
 
         // Send launch hint if we are actually launching the target. If it's already visible
         // (shouldn't happen in general) we don't need to send it.
-        if (targetActivity == null || !targetActivity.visible) {
+        if (targetActivity == null || !targetActivity.mVisibleRequested) {
             mService.mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
                     true /* forceSend */, targetActivity);
         }
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index cb41372..5a21016 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1156,6 +1156,9 @@
                 final ActivityStack focusedStack = display.getFocusedStack();
                 if (focusedStack != null) {
                     result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+                } else if (targetStack == null && !display.hasChild()) {
+                    result |= resumeHomeActivity(null /* prev */, "empty-display",
+                            display.mDisplayId);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 149bcfb..63b11ff 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -818,10 +818,6 @@
         if (mWmService.mStrictModeFlash != null) {
             mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
         }
-        if (mWmService.mCircularDisplayMask != null) {
-            mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
-                    mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
-        }
         if (mWmService.mEmulatorDisplayOverlay != null) {
             mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
                     mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 7135b21..c0432b6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -155,11 +155,11 @@
     @Override
     public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
-            Rect outStableInsets, Rect outOutsets,
+            Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState) {
         return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
-                outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
+                outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
                 outInsetsState);
     }
 
@@ -168,7 +168,7 @@
             int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
             InsetsState outInsetsState) {
         return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
-                new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */,
+                new Rect() /* outFrame */, outContentInsets, outStableInsets,
                 new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
                 outInsetsState);
     }
@@ -186,8 +186,8 @@
     @Override
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
-            Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
+            Rect outStableInsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
@@ -195,8 +195,8 @@
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
-                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
-                outStableInsets, outsets, outBackdropFrame, cutout,
+                outFrame, outContentInsets, outVisibleInsets,
+                outStableInsets, outBackdropFrame, cutout,
                 mergedConfiguration, outSurfaceControl, outInsetsState);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4038548..60b7ac0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -60,9 +60,7 @@
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
-import static com.android.server.am.TaskRecordProto.BOUNDS;
 import static com.android.server.am.TaskRecordProto.FULLSCREEN;
-import static com.android.server.am.TaskRecordProto.ID;
 import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
 import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
 import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
@@ -89,10 +87,8 @@
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
-import static com.android.server.wm.TaskProto.BOUNDS;
 import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
 import static com.android.server.wm.TaskProto.FILLS_PARENT;
-import static com.android.server.wm.TaskProto.ID;
 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
 import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
@@ -682,7 +678,7 @@
             // actual reparent.
             if (inPinnedWindowingMode()
                     && !(toStackWindowingMode == WINDOWING_MODE_UNDEFINED)
-                    && !r.isHidden()) {
+                    && r.isVisible()) {
                 r.savePinnedStackBounds();
             }
             final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
@@ -2209,7 +2205,7 @@
     void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
         for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
             final ActivityRecord r = getChildAt(activityNdx);
-            if (r.visible) {
+            if (r.mVisibleRequested) {
                 r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
             }
         }
@@ -2531,7 +2527,7 @@
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final ActivityRecord token = mChildren.get(i);
             // skip hidden (or about to hide) apps
-            if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) {
+            if (token.mIsExiting || token.isClientHidden() || !token.mVisibleRequested) {
                 continue;
             }
             final WindowState win = token.findMainWindow();
@@ -2751,7 +2747,7 @@
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final ActivityRecord token = mChildren.get(i);
             // skip hidden (or about to hide) apps
-            if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) {
+            if (!token.mIsExiting && !token.isClientHidden() && token.mVisibleRequested) {
                 return token;
             }
         }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index b1e5c8f..b3750e9 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -209,7 +209,7 @@
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
                     View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
-                    tmpRect, tmpCutout, null, mTmpInsetsState);
+                    tmpCutout, null, mTmpInsetsState);
             if (res < 0) {
                 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
                 return null;
@@ -224,7 +224,7 @@
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
-                    tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
+                    tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
                     tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
         } catch (RemoteException e) {
             // Local call.
@@ -466,8 +466,8 @@
         }
 
         @Override
-        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-                Rect stableInsets, Rect outsets, boolean reportDraw,
+        public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+                Rect stableInsets, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
                 boolean alwaysConsumeSystemBars, int displayId,
                 DisplayCutout.ParcelableWrapper displayCutout) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 3632284..6ff4b2e 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -120,7 +120,7 @@
         }
 
         mFindResults.resetTopWallpaper = true;
-        if (w.mActivityRecord != null && w.mActivityRecord.isHidden()
+        if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
                 && !w.mActivityRecord.isAnimating(TRANSITION)) {
 
             // If this window's app token is hidden and not animating, it is of no interest to us.
@@ -278,9 +278,11 @@
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
             token.hideWallpaperToken(wasDeferred, "hideWallpapers");
-            if (DEBUG_WALLPAPER_LIGHT && !token.isHidden()) Slog.d(TAG, "Hiding wallpaper " + token
-                    + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
-                    + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
+            if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) {
+                Slog.d(TAG, "Hiding wallpaper " + token
+                        + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
+                        + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
+            }
         }
     }
 
@@ -532,9 +534,9 @@
         }
 
         final boolean newTargetHidden = wallpaperTarget.mActivityRecord != null
-                && wallpaperTarget.mActivityRecord.hiddenRequested;
+                && !wallpaperTarget.mActivityRecord.mVisibleRequested;
         final boolean oldTargetHidden = prevWallpaperTarget.mActivityRecord != null
-                && prevWallpaperTarget.mActivityRecord.hiddenRequested;
+                && !prevWallpaperTarget.mActivityRecord.mVisibleRequested;
 
         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
                 + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 528cece..d23bf97 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -56,7 +56,6 @@
             final WindowState wallpaper = mChildren.get(j);
             wallpaper.hideWallpaperWindow(wasDeferred, reason);
         }
-        setHidden(true);
     }
 
     void sendWindowWallpaperCommand(
@@ -88,9 +87,7 @@
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
 
-        if (isHidden() == visible) {
-            setHidden(!visible);
-
+        if (isVisible() != visible) {
             // Need to do a layout to ensure the wallpaper now has the correct size.
             mDisplayContent.setLayoutNeeded();
         }
@@ -118,10 +115,9 @@
 
     void updateWallpaperWindows(boolean visible) {
 
-        if (isHidden() == visible) {
+        if (isVisible() != visible) {
             if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
-                    "Wallpaper token " + token + " hidden=" + !visible);
-            setHidden(!visible);
+                    "Wallpaper token " + token + " visible=" + visible);
             // Need to do a layout to ensure the wallpaper now has the correct size.
             mDisplayContent.setLayoutNeeded();
         }
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9fe4760..70fc194 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -23,10 +23,6 @@
 import static com.android.server.wm.WindowFramesProto.DECOR_FRAME;
 import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
 import static com.android.server.wm.WindowFramesProto.FRAME;
-import static com.android.server.wm.WindowFramesProto.OUTSETS;
-import static com.android.server.wm.WindowFramesProto.OUTSET_FRAME;
-import static com.android.server.wm.WindowFramesProto.OVERSCAN_FRAME;
-import static com.android.server.wm.WindowFramesProto.OVERSCAN_INSETS;
 import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
 import static com.android.server.wm.WindowFramesProto.STABLE_INSETS;
 import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
@@ -70,14 +66,6 @@
     public final Rect mDisplayFrame = new Rect();
 
     /**
-     * The region of the display frame that the display type supports displaying content on. This
-     * is mostly a special case for TV where some displays don’t have the entire display usable.
-     * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to
-     * allow window display contents to extend into the overscan region.
-     */
-    public final Rect mOverscanFrame = new Rect();
-
-    /**
      * Legacy stuff. Generally equal to the content frame expect when the IME for older apps
      * displays hint text.
      */
@@ -102,12 +90,6 @@
     public final Rect mStableFrame = new Rect();
 
     /**
-     * Frame that includes dead area outside of the surface but where we want to pretend that it's
-     * possible to draw.
-     */
-    final public Rect mOutsetFrame = new Rect();
-
-    /**
      * Similar to {@link #mDisplayFrame}
      *
      * TODO: Why is this different than mDisplayFrame
@@ -148,14 +130,6 @@
     private boolean mDisplayCutoutChanged;
 
     /**
-     * Insets that determine the area covered by the display overscan region.  These are in the
-     * application's coordinate space (without compatibility scale applied).
-     */
-    final Rect mOverscanInsets = new Rect();
-    final Rect mLastOverscanInsets = new Rect();
-    private boolean mOverscanInsetsChanged;
-
-    /**
      * Insets that determine the area covered by the stable system windows.  These are in the
      * application's coordinate space (without compatibility scale applied).
      */
@@ -164,14 +138,6 @@
     private boolean mStableInsetsChanged;
 
     /**
-     * Outsets determine the area outside of the surface where we want to pretend that it's possible
-     * to draw anyway.
-     */
-    final Rect mOutsets = new Rect();
-    final Rect mLastOutsets = new Rect();
-    private boolean mOutsetsChanged = false;
-
-    /**
      * Insets that determine the actually visible area.  These are in the application's
      * coordinate space (without compatibility scale applied).
      */
@@ -190,30 +156,25 @@
 
     private final Rect mTmpRect = new Rect();
 
-    private boolean mHasOutsets;
-
     private boolean mContentChanged;
 
     public WindowFrames() {
     }
 
-    public WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame,
-            Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame) {
-        setFrames(parentFrame, displayFrame, overscanFrame, contentFrame, visibleFrame, decorFrame,
-                stableFrame, outsetFrame);
+    public WindowFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame,
+            Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
+        setFrames(parentFrame, displayFrame, contentFrame, visibleFrame, decorFrame,
+                stableFrame);
     }
 
-    public void setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
-            Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
-            Rect outsetFrame) {
+    public void setFrames(Rect parentFrame, Rect displayFrame,
+            Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
         mParentFrame.set(parentFrame);
         mDisplayFrame.set(displayFrame);
-        mOverscanFrame.set(overscanFrame);
         mContentFrame.set(contentFrame);
         mVisibleFrame.set(visibleFrame);
         mDecorFrame.set(decorFrame);
         mStableFrame.set(stableFrame);
-        mOutsetFrame.set(outsetFrame);
     }
 
     public void setParentFrameWasClippedByDisplayCutout(
@@ -237,17 +198,6 @@
     }
 
     /**
-     * Calculates the outsets for this windowFrame. The outsets are calculated by the area between
-     * the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then
-     * {@link #mOutsets} is set to empty.
-     */
-    void calculateOutsets() {
-        if (mHasOutsets) {
-            InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
-        }
-    }
-
-    /**
      * Calculate the insets for the type
      * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
      *
@@ -301,11 +251,9 @@
      * @param scale The amount to scale the insets by.
      */
     void scaleInsets(float scale) {
-        mOverscanInsets.scale(scale);
         mContentInsets.scale(scale);
         mVisibleInsets.scale(scale);
         mStableInsets.scale(scale);
-        mOutsets.scale(scale);
     }
 
     void offsetFrames(int layoutXDiff, int layoutYDiff) {
@@ -321,15 +269,13 @@
      * @return true if info about size has changed since last reported.
      */
     boolean setReportResizeHints() {
-        mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
         mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
         mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
         mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
-        mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
         mFrameSizeChanged |= didFrameSizeChange();
         mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
-        return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
-                || mStableInsetsChanged || mOutsetsChanged || mFrameSizeChanged
+        return mContentInsetsChanged || mVisibleInsetsChanged
+                || mStableInsetsChanged || mFrameSizeChanged
                 || mDisplayCutoutChanged;
     }
 
@@ -338,11 +284,9 @@
      * after the insets are reported to client.
      */
     void resetInsetsChanged() {
-        mOverscanInsetsChanged = false;
         mContentInsetsChanged = false;
         mVisibleInsetsChanged = false;
         mStableInsetsChanged = false;
-        mOutsetsChanged = false;
         mFrameSizeChanged = false;
         mDisplayCutoutChanged = false;
     }
@@ -351,11 +295,9 @@
      * Copy over inset values as the last insets that were sent to the client.
      */
     void updateLastInsetValues() {
-        mLastOverscanInsets.set(mOverscanInsets);
         mLastContentInsets.set(mContentInsets);
         mLastVisibleInsets.set(mVisibleInsets);
         mLastStableInsets.set(mStableInsets);
-        mLastOutsets.set(mOutsets);
         mLastDisplayCutout = mDisplayCutout;
     }
 
@@ -368,19 +310,6 @@
     }
 
     /**
-     * Sets whether the frame has outsets.
-     */
-    public void setHasOutsets(boolean hasOutsets) {
-        if (mHasOutsets == hasOutsets) {
-            return;
-        }
-        mHasOutsets = hasOutsets;
-        if (!hasOutsets) {
-            mOutsets.setEmpty();
-        }
-    }
-
-    /**
      * Sets whether the content has changed. This means that either the size or parent frame has
      * changed.
      */
@@ -400,18 +329,14 @@
         mParentFrame.writeToProto(proto, PARENT_FRAME);
         mContentFrame.writeToProto(proto, CONTENT_FRAME);
         mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
-        mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
         mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
         mDecorFrame.writeToProto(proto, DECOR_FRAME);
-        mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
         mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
         mFrame.writeToProto(proto, FRAME);
         mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
         mContentInsets.writeToProto(proto, CONTENT_INSETS);
-        mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
         mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
         mStableInsets.writeToProto(proto, STABLE_INSETS);
-        mOutsets.writeToProto(proto, OUTSETS);
 
         proto.end(token);
     }
@@ -420,33 +345,26 @@
         pw.println(prefix + "Frames: containing="
                 + mContainingFrame.toShortString(sTmpSB)
                 + " parent=" + mParentFrame.toShortString(sTmpSB));
-        pw.println(prefix + "    display=" + mDisplayFrame.toShortString(sTmpSB)
-                + " overscan=" + mOverscanFrame.toShortString(sTmpSB));
+        pw.println(prefix + "    display=" + mDisplayFrame.toShortString(sTmpSB));
         pw.println(prefix + "    content=" + mContentFrame.toShortString(sTmpSB)
                 + " visible=" + mVisibleFrame.toShortString(sTmpSB));
         pw.println(prefix + "    decor=" + mDecorFrame.toShortString(sTmpSB));
-        pw.println(prefix + "    outset=" + mOutsetFrame.toShortString(sTmpSB));
         pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
                 + " last=" + mLastFrame.toShortString(sTmpSB));
         pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
                 + " last=" + mLastDisplayCutout.getDisplayCutout());
-        pw.print(prefix + "Cur insets: overscan=" + mOverscanInsets.toShortString(sTmpSB)
-                + " content=" + mContentInsets.toShortString(sTmpSB)
+        pw.print(prefix + "Cur insets: content=" + mContentInsets.toShortString(sTmpSB)
                 + " visible=" + mVisibleInsets.toShortString(sTmpSB)
-                + " stable=" + mStableInsets.toShortString(sTmpSB)
-                + " outsets=" + mOutsets.toShortString(sTmpSB));
-        pw.println(prefix + "Lst insets: overscan=" + mLastOverscanInsets.toShortString(sTmpSB)
-                + " content=" + mLastContentInsets.toShortString(sTmpSB)
+                + " stable=" + mStableInsets.toShortString(sTmpSB));
+        pw.println(prefix + "Lst insets: content=" + mLastContentInsets.toShortString(sTmpSB)
                 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
-                + " stable=" + mLastStableInsets.toShortString(sTmpSB)
-                + " outset=" + mLastOutsets.toShortString(sTmpSB));
+                + " stable=" + mLastStableInsets.toShortString(sTmpSB));
     }
 
     String getInsetsInfo() {
         return "ci=" + mContentInsets.toShortString()
                 + " vi=" + mVisibleInsets.toShortString()
-                + " si=" + mStableInsets.toShortString()
-                + " of=" + mOutsets.toShortString();
+                + " si=" + mStableInsets.toShortString();
     }
 
     String getInsetsChangedInfo() {
@@ -456,8 +374,6 @@
                 + " " + mVisibleInsets.toShortString()
                 + " stableInsetsChanged=" + mStableInsetsChanged
                 + " " + mStableInsets.toShortString()
-                + " outsetsChanged=" + mOutsetsChanged
-                + " " + mOutsets.toShortString()
                 + " displayCutoutChanged=" + mDisplayCutoutChanged;
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fc8705b..88c0fad 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
@@ -211,6 +212,8 @@
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowListener;
+import android.view.IDisplayWindowRotationController;
 import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
@@ -260,6 +263,7 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AnimationThread;
@@ -433,8 +437,10 @@
         public void onVrStateChanged(boolean enabled) {
             synchronized (mGlobalLock) {
                 mVrModeEnabled = enabled;
-                mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
-                        DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled));
+                final PooledConsumer c = PooledLambda.obtainConsumer(
+                        DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled);
+                mRoot.forAllDisplayPolicies(c);
+                c.recycle();
             }
         }
     };
@@ -591,7 +597,6 @@
 
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
-    CircularDisplayMask mCircularDisplayMask;
     EmulatorDisplayOverlay mEmulatorDisplayOverlay;
 
     final float[] mTmpFloats = new float[9];
@@ -658,6 +663,12 @@
     final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
             new WallpaperVisibilityListeners();
 
+    IDisplayWindowRotationController mDisplayRotationController = null;
+    private final DeathRecipient mDisplayRotationControllerDeath =
+            () -> mDisplayRotationController = null;
+
+    final DisplayWindowListenerController mDisplayNotificationController;
+
     boolean mDisplayFrozen = false;
     long mDisplayFreezeTime = 0;
     int mLastDisplayFreezeDuration = 0;
@@ -760,11 +771,6 @@
                 return;
             }
 
-            if (mDisplayInversionEnabledUri.equals(uri)) {
-                updateCircularDisplayMaskIfNeeded();
-                return;
-            }
-
             if (mPointerLocationUri.equals(uri)) {
                 updatePointerLocation();
                 return;
@@ -827,9 +833,11 @@
             }
             mPointerLocationEnabled = enablePointerLocation;
             synchronized (mGlobalLock) {
-                mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+                final PooledConsumer c = PooledLambda.obtainConsumer(
                         DisplayPolicy::setPointerLocationEnabled, PooledLambda.__(),
-                        mPointerLocationEnabled));
+                        mPointerLocationEnabled);
+                mRoot.forAllDisplayPolicies(c);
+                c.recycle();
             }
         }
 
@@ -1181,6 +1189,8 @@
                 PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
         mScreenFrozenLock.setReferenceCounted(false);
 
+        mDisplayNotificationController = new DisplayWindowListenerController(this);
+
         mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
         mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -1332,7 +1342,7 @@
 
     public int addWindow(Session session, IWindow client, int seq,
             LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
-            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
+            Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
             InsetsState outInsetsState) {
         int[] appOp = new int[1];
@@ -1684,7 +1694,7 @@
                 floatingStack = false;
             }
             if (displayPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack,
-                    outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
+                    outFrame, outContentInsets, outStableInsets, outDisplayCutout)) {
                 res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
             }
             outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win));
@@ -2087,8 +2097,8 @@
 
     public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility, int flags,
-            long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
+            long frameNumber, Rect outFrame, Rect outContentInsets,
+            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         int result = 0;
@@ -2380,8 +2390,8 @@
             win.updateLastInsetValues();
 
             win.getCompatFrame(outFrame);
-            win.getInsetsForRelayout(outOverscanInsets, outContentInsets, outVisibleInsets,
-                    outStableInsets, outOutsets);
+            win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
+                    outStableInsets);
             outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
             outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
             outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win));
@@ -2797,8 +2807,10 @@
 
     @Override
     public void onPowerKeyDown(boolean isScreenOn) {
-        mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
-                DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn));
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn);
+        mRoot.forAllDisplayPolicies(c);
+        c.recycle();
     }
 
     @Override
@@ -3428,26 +3440,6 @@
         }
     }
 
-    private void updateCircularDisplayMaskIfNeeded() {
-        if (mContext.getResources().getConfiguration().isScreenRound()
-                && mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_windowShowCircularMask)) {
-            final int currentUserId;
-            synchronized (mGlobalLock) {
-                currentUserId = mCurrentUserId;
-            }
-            // Device configuration calls for a circular display mask, but we only enable the mask
-            // if the accessibility color inversion feature is disabled, as the inverted mask
-            // causes artifacts.
-            int inversionState = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId);
-            int showMask = (inversionState == 1) ? 0 : 1;
-            Message m = mH.obtainMessage(H.SHOW_CIRCULAR_DISPLAY_MASK);
-            m.arg1 = showMask;
-            mH.sendMessage(m);
-        }
-    }
-
     public void showEmulatorDisplayOverlayIfNeeded() {
         if (mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_windowEnableCircularEmulatorDisplayOverlay)
@@ -3457,35 +3449,6 @@
         }
     }
 
-    public void showCircularMask(boolean visible) {
-        synchronized (mGlobalLock) {
-            if (visible) {
-                // TODO(multi-display): support multiple displays
-                if (mCircularDisplayMask == null) {
-                    int screenOffset = mContext.getResources().getInteger(
-                            com.android.internal.R.integer.config_windowOutsetBottom);
-                    int maskThickness = mContext.getResources().getDimensionPixelSize(
-                            com.android.internal.R.dimen.circular_display_mask_thickness);
-
-
-                    if (SHOW_LIGHT_TRANSACTIONS) {
-                        Slog.i(TAG_WM,
-                                ">>> showCircularMask(visible=" + visible + ")");
-                    }
-                    mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory,
-                            getDefaultDisplayContentLocked(), mPolicy.getWindowLayerFromTypeLw(
-                            WindowManager.LayoutParams.TYPE_POINTER) * TYPE_LAYER_MULTIPLIER
-                            + 10, screenOffset, maskThickness, mTransaction);
-                }
-                mCircularDisplayMask.setVisibility(true, mTransaction);
-            } else if (mCircularDisplayMask != null) {
-                mCircularDisplayMask.setVisibility(false, mTransaction);
-                mCircularDisplayMask = null;
-            }
-            mTransaction.apply();
-        }
-    }
-
     public void showEmulatorDisplayOverlay() {
         synchronized (mGlobalLock) {
 
@@ -3781,6 +3744,27 @@
     }
 
     @Override
+    public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) {
+        if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+        }
+        try {
+            synchronized (mGlobalLock) {
+                if (mDisplayRotationController != null) {
+                    mDisplayRotationController.asBinder().unlinkToDeath(
+                            mDisplayRotationControllerDeath, 0);
+                    mDisplayRotationController = null;
+                }
+                controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0);
+                mDisplayRotationController = controller;
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Unable to set rotation controller");
+        }
+    }
+
+    @Override
     public int watchRotation(IRotationWatcher watcher, int displayId) {
         final DisplayContent displayContent;
         synchronized (mGlobalLock) {
@@ -3944,6 +3928,31 @@
         }
     }
 
+    /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */
+    @Override
+    public void registerDisplayWindowListener(IDisplayWindowListener listener) {
+        if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mDisplayNotificationController.registerListener(listener);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /** Unregister a hierarchy listener so that it stops receiving callbacks. */
+    @Override
+    public void unregisterDisplayWindowListener(IDisplayWindowListener listener) {
+        if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+        }
+        mDisplayNotificationController.unregisterListener(listener);
+    }
+
     @Override
     public int getPreferredOptionsPanelGravity(int displayId) {
         synchronized (mGlobalLock) {
@@ -4436,8 +4445,6 @@
             mActivityTaskManager.updateConfiguration(null);
         } catch (RemoteException e) {
         }
-
-        updateCircularDisplayMaskIfNeeded();
     }
 
     public void systemReady() {
@@ -4520,7 +4527,6 @@
 
         public static final int NEW_ANIMATOR_SCALE = 34;
 
-        public static final int SHOW_CIRCULAR_DISPLAY_MASK = 35;
         public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
 
         public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
@@ -4754,11 +4760,6 @@
                     break;
                 }
 
-                case SHOW_CIRCULAR_DISPLAY_MASK: {
-                    showCircularMask(msg.arg1 == 1);
-                    break;
-                }
-
                 case SHOW_EMULATOR_DISPLAY_OVERLAY: {
                     showEmulatorDisplayOverlay();
                     break;
@@ -5168,38 +5169,6 @@
     }
 
     @Override
-    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
-        if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-                if (displayContent != null) {
-                    setOverscanLocked(displayContent, left, top, right, bottom);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    private void setOverscanLocked(DisplayContent displayContent,
-            int left, int top, int right, int bottom) {
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        displayInfo.overscanLeft = left;
-        displayInfo.overscanTop = top;
-        displayInfo.overscanRight = right;
-        displayInfo.overscanBottom = bottom;
-
-        mDisplayWindowSettings.setOverscanLocked(displayInfo, left, top, right, bottom);
-
-        displayContent.reconfigureDisplayLocked();
-    }
-
-    @Override
     public void startWindowTrace(){
         mWindowTracing.startTrace(null /* printwriter */);
     }
@@ -5623,8 +5592,10 @@
                     + android.Manifest.permission.STATUS_BAR);
         }
         synchronized (mGlobalLock) {
-            mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
-                    DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show));
+            final PooledConsumer c = PooledLambda.obtainConsumer(
+                    DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show);
+            mRoot.forAllDisplayPolicies(c);
+            c.recycle();
         }
     }
 
@@ -7564,8 +7535,10 @@
     void onLockTaskStateChanged(int lockTaskState) {
         // TODO: pass in displayId to determine which display the lock task state changed
         synchronized (mGlobalLock) {
-            mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
-                    DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState));
+            final PooledConsumer c = PooledLambda.obtainConsumer(
+                    DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState);
+            mRoot.forAllDisplayPolicies(c);
+            c.recycle();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index e01cbf2..8e955cf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -66,8 +66,6 @@
                     return runDisplayDensity(pw);
                 case "folded-area":
                     return runDisplayFoldedArea(pw);
-                case "overscan":
-                    return runDisplayOverscan(pw);
                 case "scaling":
                     return runDisplayScaling(pw);
                 case "dismiss-keyguard":
@@ -247,30 +245,6 @@
         return 0;
     }
 
-    private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
-        String overscanStr = getNextArgRequired();
-        Rect rect = new Rect();
-        final int displayId = getDisplayId(overscanStr);
-        if ("reset".equals(overscanStr)) {
-            rect.set(0, 0, 0, 0);
-        } else {
-            final Pattern FLATTENED_PATTERN = Pattern.compile(
-                    "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
-            Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
-            if (!matcher.matches()) {
-                getErrPrintWriter().println("Error: bad rectangle arg: " + overscanStr);
-                return -1;
-            }
-            rect.left = Integer.parseInt(matcher.group(1));
-            rect.top = Integer.parseInt(matcher.group(2));
-            rect.right = Integer.parseInt(matcher.group(3));
-            rect.bottom = Integer.parseInt(matcher.group(4));
-        }
-
-        mInterface.setOverscan(displayId, rect.left, rect.top, rect.right, rect.bottom);
-        return 0;
-    }
-
     private int runDisplayScaling(PrintWriter pw) throws RemoteException {
         String scalingStr = getNextArgRequired();
         if ("auto".equals(scalingStr)) {
@@ -380,8 +354,6 @@
         pw.println("    Return or override display density.");
         pw.println("  folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]");
         pw.println("    Return or override folded area.");
-        pw.println("  overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
-        pw.println("    Set overscan area for display.");
         pw.println("  scaling [off|auto] [-d DISPLAY_ID]");
         pw.println("    Set display scaling mode.");
         pw.println("  dismiss-keyguard");
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d63fbc21..2e188b7 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -533,7 +533,7 @@
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             for (int i = mActivities.size() - 1; i >= 0; --i) {
                 final ActivityRecord r = mActivities.get(i);
-                if (r.visible) {
+                if (r.mVisibleRequested) {
                     return true;
                 }
             }
@@ -555,7 +555,7 @@
                 continue;
             }
             ActivityRecord topActivity = task.getTopActivity();
-            if (topActivity != null && topActivity.visible) {
+            if (topActivity != null && topActivity.mVisibleRequested) {
                 return true;
             }
         }
@@ -589,7 +589,7 @@
         // - no longer visible OR
         // - not focusable (in PiP mode for instance)
         if (topDisplay == null
-                || !mPreQTopResumedActivity.visible
+                || !mPreQTopResumedActivity.mVisibleRequested
                 || !mPreQTopResumedActivity.isFocusable()) {
             canUpdate = true;
         }
@@ -739,7 +739,7 @@
             }
             // Don't consider any activities that are currently not in a state where they
             // can be destroyed.
-            if (r.visible || !r.stopped || !r.hasSavedState()
+            if (r.mVisibleRequested || !r.stopped || !r.hasSavedState()
                     || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
                 continue;
@@ -793,7 +793,7 @@
                         continue;
                     }
                 }
-                if (r.visible) {
+                if (r.mVisibleRequested) {
                     final Task task = r.getTask();
                     if (task != null && minTaskLayer > 0) {
                         final int layer = task.mLayerRank;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d590572..fb6b7c1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1047,9 +1047,6 @@
 
         applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
 
-        // Calculate the outsets before the content frame gets shrinked to the window frame.
-        mWindowFrames.calculateOutsets();
-
         // Make sure the content and visible frames are inside of the
         // final window frame.
         if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) {
@@ -1094,13 +1091,6 @@
                     Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom));
         }
 
-        if (isFullscreenAndFillsDisplay && !windowsAreFloating) {
-            // Windows that are not fullscreen can be positioned outside of the display frame,
-            // but that is not a reason to provide them with overscan insets.
-            InsetUtils.insetsBetweenFrames(layoutContainingFrame, mWindowFrames.mOverscanFrame,
-                    mWindowFrames.mOverscanInsets);
-        }
-
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
             final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo(
                     mWindowFrames.mDisplayFrame);
@@ -1170,11 +1160,6 @@
     }
 
     @Override
-    public Rect getOverscanFrameLw() {
-        return mWindowFrames.mOverscanFrame;
-    }
-
-    @Override
     public Rect getContentFrameLw() {
         return mWindowFrames.mContentFrame;
     }
@@ -1554,7 +1539,7 @@
      */
     // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this?
     boolean isWinVisibleLw() {
-        return (mActivityRecord == null || !mActivityRecord.hiddenRequested
+        return (mActivityRecord == null || mActivityRecord.mVisibleRequested
                 || mActivityRecord.isAnimating(TRANSITION)) && isVisible();
     }
 
@@ -1563,7 +1548,7 @@
      * not the pending requested hidden state.
      */
     boolean isVisibleNow() {
-        return (!mToken.isHidden() || mAttrs.type == TYPE_APPLICATION_STARTING)
+        return (mToken.isVisible() || mAttrs.type == TYPE_APPLICATION_STARTING)
                 && isVisible();
     }
 
@@ -1585,7 +1570,7 @@
         final ActivityRecord atoken = mActivityRecord;
         return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                 && isVisibleByPolicy() && !isParentWindowHidden()
-                && (atoken == null || !atoken.hiddenRequested)
+                && (atoken == null || atoken.mVisibleRequested)
                 && !mAnimatingExit && !mDestroying;
     }
 
@@ -1600,7 +1585,7 @@
         }
         final ActivityRecord atoken = mActivityRecord;
         if (atoken != null) {
-            return ((!isParentWindowHidden() && !atoken.hiddenRequested)
+            return ((!isParentWindowHidden() && atoken.mVisibleRequested)
                     || isAnimating(TRANSITION | PARENTS));
         }
         return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
@@ -1636,7 +1621,7 @@
             return false;
         }
         final boolean parentAndClientVisible = !isParentWindowHidden()
-                && mViewVisibility == View.VISIBLE && !mToken.isHidden();
+                && mViewVisibility == View.VISIBLE && mToken.isVisible();
         return mHasSurface && isVisibleByPolicy() && !mDestroying
                 && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
     }
@@ -1655,7 +1640,7 @@
         } else {
             final Task task = getTask();
             final boolean canFromTask = task != null && task.canAffectSystemUiFlags();
-            return canFromTask && !mActivityRecord.isHidden();
+            return canFromTask && mActivityRecord.isVisible();
         }
     }
 
@@ -1667,7 +1652,7 @@
     public boolean isDisplayedLw() {
         final ActivityRecord atoken = mActivityRecord;
         return isDrawnLw() && isVisibleByPolicy()
-                && ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested))
+                && ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested))
                         || isAnimating(TRANSITION | PARENTS));
     }
 
@@ -1684,8 +1669,8 @@
         final ActivityRecord atoken = mActivityRecord;
         return mViewVisibility == View.GONE
                 || !mRelayoutCalled
-                || (atoken == null && mToken.isHidden())
-                || (atoken != null && atoken.hiddenRequested)
+                || (atoken == null && !mToken.isVisible())
+                || (atoken != null && !atoken.mVisibleRequested)
                 || isParentWindowGoneForLayout()
                 || (mAnimatingExit && !isAnimatingLw())
                 || mDestroying;
@@ -2177,7 +2162,8 @@
                         + " parentHidden=" + isParentWindowHidden()
                         + " exiting=" + mAnimatingExit + " destroying=" + mDestroying);
                 if (mActivityRecord != null) {
-                    Slog.i(TAG_WM, "  mActivityRecord.hiddenRequested=" + mActivityRecord.hiddenRequested);
+                    Slog.i(TAG_WM, "  mActivityRecord.visibleRequested="
+                            + mActivityRecord.mVisibleRequested);
                 }
             }
         }
@@ -2625,14 +2611,14 @@
         return showBecauseOfActivity || showBecauseOfWindow;
     }
 
-    /** @return false if this window desires touch events. */
+    /** @return {@code false} if this window desires touch events. */
     boolean cantReceiveTouchInput() {
         if (mActivityRecord == null || mActivityRecord.getTask() == null) {
             return false;
         }
 
         return mActivityRecord.getTask().getTaskStack().shouldIgnoreInput()
-                || mActivityRecord.hiddenRequested
+                || !mActivityRecord.mVisibleRequested
                 || isAnimatingToRecents();
     }
 
@@ -3265,11 +3251,9 @@
             }
 
             final Rect frame = mWindowFrames.mCompatFrame;
-            final Rect overscanInsets = mWindowFrames.mLastOverscanInsets;
             final Rect contentInsets = mWindowFrames.mLastContentInsets;
             final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
             final Rect stableInsets = mWindowFrames.mLastStableInsets;
-            final Rect outsets = mWindowFrames.mLastOutsets;
             final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
             final boolean reportOrientation = mReportOrientationChanged;
             final int displayId = getDisplayId();
@@ -3281,8 +3265,8 @@
                     @Override
                     public void run() {
                         try {
-                            dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
-                                    stableInsets, outsets, reportDraw, mergedConfiguration,
+                            dispatchResized(frame, contentInsets, visibleInsets,
+                                    stableInsets, reportDraw, mergedConfiguration,
                                     reportOrientation, displayId, displayCutout);
                         } catch (RemoteException e) {
                             // Not a remote call, RemoteException won't be raised.
@@ -3290,8 +3274,8 @@
                     }
                 });
             } else {
-                dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                        outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
+                dispatchResized(frame, contentInsets, visibleInsets, stableInsets,
+                        reportDraw, mergedConfiguration, reportOrientation, displayId,
                         displayCutout);
             }
             if (mWmService.mAccessibilityController != null) {
@@ -3423,14 +3407,14 @@
         return stack.mStackId;
     }
 
-    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+    private void dispatchResized(Rect frame, Rect contentInsets,
+            Rect visibleInsets, Rect stableInsets, boolean reportDraw,
             MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
             DisplayCutout displayCutout)
             throws RemoteException {
         final boolean forceRelayout = isDragResizeChanged() || reportOrientation;
 
-        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+        mClient.resized(frame, contentInsets, visibleInsets, stableInsets,
                 reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
                 getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this), displayId,
                 new DisplayCutout.ParcelableWrapper(displayCutout));
@@ -4163,9 +4147,9 @@
                     + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING)
                     + " during animation: policyVis=" + isVisibleByPolicy()
                     + " parentHidden=" + isParentWindowHidden()
-                    + " tok.hiddenRequested="
-                    + (mActivityRecord != null && mActivityRecord.hiddenRequested)
-                    + " tok.hidden=" + (mActivityRecord != null && mActivityRecord.isHidden())
+                    + " tok.visibleRequested="
+                    + (mActivityRecord != null && mActivityRecord.mVisibleRequested)
+                    + " tok.visible=" + (mActivityRecord != null && mActivityRecord.isVisible())
                     + " animating=" + isAnimating(TRANSITION | PARENTS)
                     + " tok animating="
                     + (mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION))
@@ -4572,7 +4556,7 @@
                         + " pv=" + isVisibleByPolicy()
                         + " mDrawState=" + mWinAnimator.mDrawState
                         + " ph=" + isParentWindowHidden()
-                        + " th=" + (mActivityRecord != null ? mActivityRecord.hiddenRequested : false)
+                        + " th=" + (mActivityRecord != null && mActivityRecord.mVisibleRequested)
                         + " a=" + isAnimating(TRANSITION | PARENTS));
             }
         }
@@ -5282,13 +5266,11 @@
     /**
      * Copy the inset values over so they can be sent back to the client when a relayout occurs.
      */
-    void getInsetsForRelayout(Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets, Rect outOutsets) {
-        outOverscanInsets.set(mWindowFrames.mOverscanInsets);
+    void getInsetsForRelayout(Rect outContentInsets, Rect outVisibleInsets,
+            Rect outStableInsets) {
         outContentInsets.set(mWindowFrames.mContentInsets);
         outVisibleInsets.set(mWindowFrames.mVisibleInsets);
         outStableInsets.set(mWindowFrames.mStableInsets);
-        outOutsets.set(mWindowFrames.mOutsets);
 
         mLastRelayoutContentInsets.set(mWindowFrames.mContentInsets);
     }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 88a1458..6480a15 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -29,7 +29,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowTokenProto.HASH_CODE;
-import static com.android.server.wm.WindowTokenProto.HIDDEN;
 import static com.android.server.wm.WindowTokenProto.PAUSED;
 import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
 import static com.android.server.wm.WindowTokenProto.WINDOWS;
@@ -72,9 +71,6 @@
     // Is key dispatching paused for this token?
     boolean paused = false;
 
-    // Should this token's windows be hidden?
-    private boolean mHidden;
-
     // Temporary for finding which tokens no longer have visible windows.
     boolean hasVisible;
 
@@ -128,16 +124,6 @@
         }
     }
 
-    void setHidden(boolean hidden) {
-        if (hidden != mHidden) {
-            mHidden = hidden;
-        }
-    }
-
-    boolean isHidden() {
-        return mHidden;
-    }
-
     void removeAllWindowsIfPossible() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowState win = mChildren.get(i);
@@ -156,7 +142,7 @@
         // This token is exiting, so allow it to be removed when it no longer contains any windows.
         mPersistOnEmpty = false;
 
-        if (mHidden) {
+        if (!isVisible()) {
             return;
         }
 
@@ -169,7 +155,10 @@
             changed |= win.onSetAppExiting();
         }
 
-        setHidden(true);
+        final ActivityRecord app = asActivityRecord();
+        if (app != null) {
+            app.setVisible(false);
+        }
 
         if (changed) {
             mWmService.mWindowPlacerLocked.performSurfacePlacement();
@@ -286,7 +275,6 @@
             final WindowState w = mChildren.get(i);
             w.writeToProto(proto, WINDOWS, logLevel);
         }
-        proto.write(HIDDEN, mHidden);
         proto.write(WAITING_TO_SHOW, waitingToShow);
         proto.write(PAUSED, paused);
         proto.end(token);
@@ -296,8 +284,7 @@
         super.dump(pw, prefix, dumpAll);
         pw.print(prefix); pw.print("windows="); pw.println(mChildren);
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
-                pw.print(" hidden="); pw.print(mHidden);
-                pw.print(" hasVisible="); pw.println(hasVisible);
+        pw.print(" hasVisible="); pw.println(hasVisible);
         if (waitingToShow || sendingToBottom) {
             pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
                     pw.print(" sendingToBottom="); pw.print(sendingToBottom);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a39cc20..9dac03f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4928,21 +4928,25 @@
 
     @Override
     @PasswordComplexity
-    public int getPasswordComplexity() {
+    public int getPasswordComplexity(boolean parent) {
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.GET_USER_PASSWORD_COMPLEXITY_LEVEL)
                 .setStrings(mInjector.getPackageManager()
                         .getPackagesForUid(mInjector.binderGetCallingUid()))
                 .write();
         final int callingUserId = mInjector.userHandleGetCallingUserId();
+
+        if (parent) {
+            enforceProfileOwnerOrSystemUser();
+        }
         enforceUserUnlocked(callingUserId);
         mContext.enforceCallingOrSelfPermission(
                 REQUEST_PASSWORD_COMPLEXITY,
                 "Must have " + REQUEST_PASSWORD_COMPLEXITY + " permission.");
 
         synchronized (getLockObject()) {
-            int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false);
-            PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(targetUserId);
+            final int credentialOwner = getCredentialOwner(callingUserId, parent);
+            PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
             return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity();
         }
     }
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 f571411..f270724 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5295,13 +5295,17 @@
         });
     }
 
-    public void testGetPasswordComplexity_securityExceptionIfParentInstance() {
-        assertThrows(SecurityException.class,
-                () -> new DevicePolicyManagerTestable(
-                        mServiceContext,
-                        dpms,
-                        /* parentInstance= */ true)
-                        .getPasswordComplexity());
+    public void testGetPasswordComplexity_securityExceptionNotThrownForParentInstance() {
+        mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
+        setAsProfileOwner(admin1);
+
+        new DevicePolicyManagerTestable(
+                mServiceContext,
+                dpms,
+                /* parentInstance= */ true)
+                .getPasswordComplexity();
+
+        assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity());
     }
 
     public void testGetPasswordComplexity_illegalStateExceptionIfLocked() {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
index 86e544d..975689d 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -18,9 +18,10 @@
 
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.OpenFormula;
 import com.android.server.integrity.model.Rule;
 
 import org.junit.Test;
@@ -29,86 +30,416 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(JUnit4.class)
 public class RuleXmlParserTest {
 
-    private static final String VALID_RULE_XML = "<RuleList>"
-            + "<Rule>"
-            + "<OpenFormula>"
-            + "<Connector>NOT</Connector>"
-            + "<AtomicFormula>"
-            + "<Key>PACKAGE_NAME</Key>"
-            + "<Operator>EQ</Operator>"
-            + "<Value>com.app.test</Value>"
-            + "</AtomicFormula>"
-            + "</OpenFormula>"
-            + "<Effect>DENY</Effect>"
-            + "</Rule>"
-            + "</RuleList>";
-
     @Test
-    public void testXmlString_validRule() {
+    public void testXmlStream_validOpenFormula() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
         RuleParser xmlParser = new RuleXmlParser();
-
-        List<Rule> rules = xmlParser.parse(VALID_RULE_XML);
-
-        assertNotNull(rules);
-        assertTrue(rules.isEmpty());
-    }
-
-    @Test
-    public void testXmlStream_validRule() {
-        RuleParser xmlParser = new RuleXmlParser();
-        InputStream inputStream = new ByteArrayInputStream(VALID_RULE_XML.getBytes());
+        InputStream inputStream = new ByteArrayInputStream(ruleXmlOpenFormula.getBytes());
+        Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+                Rule.DENY);
 
         List<Rule> rules = xmlParser.parse(inputStream);
 
-        assertNotNull(rules);
-        assertTrue(rules.isEmpty());
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validOpenFormula_notConnector() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validOpenFormula_andConnector() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.AND + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>test_cert</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(new OpenFormula(OpenFormula.AND, Arrays.asList(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validOpenFormula_orConnector() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.OR + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>test_cert</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(new OpenFormula(OpenFormula.OR, Arrays.asList(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validOpenFormula_differentTagOrder() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_invalidOpenFormula_invalidNumberOfFormulas() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>1</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
+                () -> xmlParser.parse(ruleXmlOpenFormula));
+    }
+
+    @Test
+    public void testXmlString_invalidOpenFormula_invalidOperator() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>INVALID_OPERATOR</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "For input string: \"INVALID_OPERATOR\"",
+                () -> xmlParser.parse(ruleXmlOpenFormula));
+    }
+
+    @Test
+    public void testXmlString_invalidOpenFormula_invalidEffect() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>INVALID_EFFECT</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "For input string: \"INVALID_EFFECT\"",
+                () -> xmlParser.parse(ruleXmlOpenFormula));
+    }
+
+    @Test
+    public void testXmlString_invalidOpenFormula_invalidTags() throws Exception {
+        String ruleXmlOpenFormula = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<InvalidConnector>" + OpenFormula.NOT + "</InvalidConnector>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidConnector",
+                () -> xmlParser.parse(ruleXmlOpenFormula));
+    }
+
+    @Test
+    public void testXmlString_validAtomicFormula_stringValue() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validAtomicFormula_integerValue() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>1</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(
+                new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validAtomicFormula_booleanValue() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>true</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(
+                new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_validAtomicFormula_differentTagOrder() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+        Rule expectedRule = new Rule(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                Rule.DENY);
+
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testXmlString_invalidAtomicFormula_invalidTags() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<BadKey>" + AtomicFormula.PACKAGE_NAME + "</BadKey>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Found unexpected tag: BadKey",
+                () -> xmlParser.parse(ruleXmlAtomicFormula));
+    }
+
+    @Test
+    public void testXmlString_invalidAtomicFormula() throws Exception {
+        String ruleXmlAtomicFormula = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+        RuleParser xmlParser = new RuleXmlParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "For input string: \"com.app.test\"",
+                () -> xmlParser.parse(ruleXmlAtomicFormula));
     }
 
     @Test
     public void testXmlString_withNoRuleList() {
-        String ruleXmlWithNoRuleList = "<Rule>"
-                + "<OpenFormula>"
-                + "<Connector>NOT</Connector>"
-                + "<AtomicFormula>"
-                + "<Key>PACKAGE_NAME</Key>"
-                + "<Operator>EQ</Operator>"
-                + "<Value>com.app.test</Value>"
-                + "</AtomicFormula>"
-                + "</OpenFormula>"
-                + "<Effect>DENY</Effect>"
-                + "</Rule>";
+        String ruleXmlWithNoRuleList = "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>";
         RuleParser xmlParser = new RuleXmlParser();
 
         assertExpectException(
-                RuntimeException.class,
-                /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
                 () -> xmlParser.parse(ruleXmlWithNoRuleList));
     }
 
     @Test
     public void testXmlStream_withNoRuleList() {
-        String ruleXmlWithNoRuleList = "<Rule>"
-                + "<OpenFormula>"
-                + "<Connector>NOT</Connector>"
-                + "<AtomicFormula>"
-                + "<Key>PACKAGE_NAME</Key>"
-                + "<Operator>EQ</Operator>"
-                + "<Value>com.app.test</Value>"
-                + "</AtomicFormula>"
-                + "</OpenFormula>"
-                + "<Effect>DENY</Effect>"
-                + "</Rule>";
+        String ruleXmlWithNoRuleList = "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>";
         InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
         RuleParser xmlParser = new RuleXmlParser();
 
         assertExpectException(
-                RuntimeException.class,
-                /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
                 () -> xmlParser.parse(inputStream));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
new file mode 100644
index 0000000..082fda8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -0,0 +1,298 @@
+/*
+ * 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.integrity.serializer;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.integrity.model.AppInstallMetadata;
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
+import com.android.server.integrity.model.Rule;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(JUnit4.class)
+public class RuleXmlSerializerTest {
+
+    @Test
+    public void testXmlString_serializeEmptyRule() throws Exception {
+        Rule rule = null;
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL />";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
+        Rule rule1 = null;
+        Rule rule2 = new Rule(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Arrays.asList(rule1, rule2));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlStream_serializeValidOpenFormula() throws Exception {
+        Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
+                Collections.singletonList(
+                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+                                "com.app.test"))), Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        OutputStream outputStream = new ByteArrayOutputStream();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        xmlSerializer.serialize(Collections.singletonList(rule), outputStream);
+
+        String actualRules = outputStream.toString();
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidOpenFormula_notConnector() throws Exception {
+        Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
+                Collections.singletonList(
+                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+                                "com.app.test"))), Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.NOT + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidOpenFormula_andConnector() throws Exception {
+        Rule rule = new Rule(new OpenFormula(OpenFormula.AND,
+                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+                                "com.app.test"),
+                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
+                                "test_cert"))), Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.AND + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+                + "<V>test_cert</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidOpenFormula_orConnector() throws Exception {
+        Rule rule = new Rule(new OpenFormula(OpenFormula.OR,
+                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+                                "com.app.test"),
+                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
+                                "test_cert"))), Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<OF>"
+                + "<C>" + OpenFormula.OR + "</C>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+                + "<V>test_cert</V>"
+                + "</AF>"
+                + "</OF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidAtomicFormula_stringValue() throws Exception {
+        Rule rule = new Rule(
+                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+                Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+                + "<V>com.app.test</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception {
+        Rule rule = new Rule(
+                new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+                Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+                + "<O>" + AtomicFormula.EQ + "</O>"
+                + "<V>1</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeValidAtomicFormula_booleanValue() throws Exception {
+        Rule rule = new Rule(
+                new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+        String expectedRules = "<RL>"
+                + "<R>"
+                + "<AF>"
+                + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>"
+                + "<V>true</V>"
+                + "</AF>"
+                + "<E>" + Rule.DENY + "</E>"
+                + "</R>"
+                + "</RL>";
+
+        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+        assertEquals(expectedRules, actualRules);
+    }
+
+    @Test
+    public void testXmlString_serializeInvalidFormulaType() throws Exception {
+        Formula invalidFormula = getInvalidFormula();
+        Rule rule = new Rule(invalidFormula, Rule.DENY);
+        RuleSerializer xmlSerializer = new RuleXmlSerializer();
+
+        assertExpectException(
+                RuleSerializeException.class,
+                /* expectedExceptionMessageRegex */ "Invalid formula type",
+                () -> xmlSerializer.serialize(Collections.singletonList(rule)));
+    }
+
+    private Formula getInvalidFormula() {
+        return new Formula() {
+            @Override
+            public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+                return false;
+            }
+
+            @Override
+            public int hashCode() {
+                return super.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return super.equals(obj);
+            }
+
+            @NonNull
+            @Override
+            protected Object clone() throws CloneNotSupportedException {
+                return super.clone();
+            }
+
+            @Override
+            public String toString() {
+                return super.toString();
+            }
+
+            @Override
+            protected void finalize() throws Throwable {
+                super.finalize();
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 3c10447..b751308 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -156,6 +156,8 @@
         if (isMultiPackage) {
             params.isMultiPackage = true;
         }
+        InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller",
+                false);
         return new PackageInstallerSession(
                 /* callback */ null,
                 /* context */null,
@@ -166,7 +168,7 @@
                 /* sessionId */ sessionId,
                 /* userId */  456,
                 /* installerUid */ -1,
-                /* installSource */ InstallSource.create("testInstaller", "testInstaller"),
+                /* installSource */ installSource,
                 /* sessionParams */ params,
                 /* createdMillis */ 0L,
                 /* stageDir */ mTmpDir,
diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
deleted file mode 100644
index d1ac19c..0000000
--- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.stats;
-
-import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline;
-import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
-
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-
-/**
- * Build/Install/Run:
- *  atest FrameworksServicesTests:ProcfsMemoryUtilTest
- */
-@SmallTest
-public class ProcfsMemoryUtilTest {
-    private static final String STATUS_CONTENTS = "Name:\tandroid.youtube\n"
-            + "State:\tS (sleeping)\n"
-            + "Tgid:\t12088\n"
-            + "Pid:\t12088\n"
-            + "PPid:\t723\n"
-            + "TracerPid:\t0\n"
-            + "Uid:\t10083\t10083\t10083\t10083\n"
-            + "Gid:\t10083\t10083\t10083\t10083\n"
-            + "Ngid:\t0\n"
-            + "FDSize:\t128\n"
-            + "Groups:\t3003 9997 20083 50083 \n"
-            + "VmPeak:\t 4546844 kB\n"
-            + "VmSize:\t 4542636 kB\n"
-            + "VmLck:\t       0 kB\n"
-            + "VmPin:\t       0 kB\n"
-            + "VmHWM:\t  137668 kB\n" // RSS high-water mark
-            + "VmRSS:\t  126776 kB\n" // RSS
-            + "RssAnon:\t   37860 kB\n"
-            + "RssFile:\t   88764 kB\n"
-            + "RssShmem:\t     152 kB\n"
-            + "VmData:\t 4125112 kB\n"
-            + "VmStk:\t    8192 kB\n"
-            + "VmExe:\t      24 kB\n"
-            + "VmLib:\t  102432 kB\n"
-            + "VmPTE:\t    1300 kB\n"
-            + "VmPMD:\t      36 kB\n"
-            + "VmSwap:\t      22 kB\n" // Swap
-            + "Threads:\t95\n"
-            + "SigQ:\t0/13641\n"
-            + "SigPnd:\t0000000000000000\n"
-            + "ShdPnd:\t0000000000000000\n"
-            + "SigBlk:\t0000000000001204\n"
-            + "SigIgn:\t0000000000000001\n"
-            + "SigCgt:\t00000006400084f8\n"
-            + "CapInh:\t0000000000000000\n"
-            + "CapPrm:\t0000000000000000\n"
-            + "CapEff:\t0000000000000000\n"
-            + "CapBnd:\t0000000000000000\n"
-            + "CapAmb:\t0000000000000000\n"
-            + "Seccomp:\t2\n"
-            + "Cpus_allowed:\tff\n"
-            + "Cpus_allowed_list:\t0-7\n"
-            + "Mems_allowed:\t1\n"
-            + "Mems_allowed_list:\t0\n"
-            + "voluntary_ctxt_switches:\t903\n"
-            + "nonvoluntary_ctxt_switches:\t104\n";
-
-    @Test
-    public void testParseMemorySnapshotFromStatus_parsesCorrectValue() {
-        MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS);
-        assertThat(snapshot.uid).isEqualTo(10083);
-        assertThat(snapshot.rssHighWaterMarkInKilobytes).isEqualTo(137668);
-        assertThat(snapshot.rssInKilobytes).isEqualTo(126776);
-        assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860);
-        assertThat(snapshot.swapInKilobytes).isEqualTo(22);
-    }
-
-    @Test
-    public void testParseMemorySnapshotFromStatus_invalidValue() {
-        MemorySnapshot snapshot =
-                parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest");
-        assertThat(snapshot).isNull();
-    }
-
-    @Test
-    public void testParseMemorySnapshotFromStatus_emptyContents() {
-        MemorySnapshot snapshot = parseMemorySnapshotFromStatus("");
-        assertThat(snapshot).isNull();
-    }
-
-    @Test
-    public void testParseCmdline_invalidValue() {
-        byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
-
-        assertThat(parseCmdline(bytesToString(nothing))).isEmpty();
-    }
-
-    @Test
-    public void testParseCmdline_correctValue_noNullBytes() {
-        assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app");
-    }
-
-    @Test
-    public void testParseCmdline_correctValue_withNullBytes() {
-        byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
-
-        assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
-
-        // test\0\0test
-        byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
-
-        assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
-    }
-
-    @Test
-    public void testParseCmdline_emptyContents() {
-        assertThat(parseCmdline("")).isEmpty();
-    }
-
-    private static String bytesToString(byte[] bytes) {
-        ByteArrayOutputStream output = new ByteArrayOutputStream();
-        output.write(bytes, 0, bytes.length);
-        return output.toString();
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 36504ac..4a13dce 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -28,7 +28,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.app.usage.UsageStatsManager;
 import android.os.FileUtils;
 import android.test.AndroidTestCase;
 
@@ -150,4 +149,21 @@
         aih = new AppIdleHistory(mStorageDir, 5000);
         assertEquals(REASON_MAIN_TIMEOUT, aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000));
     }
+
+    public void testNullPackage() throws Exception {
+        AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
+        // Report usage of a package
+        aih.reportUsage(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+                REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0);
+        // "Accidentally" report usage against a null named package
+        aih.reportUsage(null, USER_ID, STANDBY_BUCKET_ACTIVE,
+                REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0);
+        // Persist data
+        aih.writeAppIdleTimes(USER_ID);
+        // Recover data from disk
+        aih = new AppIdleHistory(mStorageDir, 5000);
+        // Verify data is intact
+        assertEquals(REASON_MAIN_USAGE | REASON_SUB_USAGE_MOVE_TO_FOREGROUND,
+                aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000));
+    }
 }
\ No newline at end of file
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 9df7b45..e560cb9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -346,7 +346,7 @@
                 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         activity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
         activity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-        activity.visible = true;
+        activity.mVisibleRequested = true;
         activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
 
         final ArrayList<CompletableFuture<IBinder>> resultWrapper = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 3c619f7..734761f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -160,7 +160,7 @@
     public void testOnActivityLaunchCancelled_hasDrawn() {
         onActivityLaunched();
 
-        mTopActivity.visible = mTopActivity.mDrawn = true;
+        mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
 
         // Cannot time already-visible activities.
         mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
@@ -171,7 +171,7 @@
 
     @Test
     public void testOnActivityLaunchCancelled_finishedBeforeDrawn() {
-        mTopActivity.visible = mTopActivity.mDrawn = true;
+        mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
 
         // Suppress resume when creating the record because we want to notify logger manually.
         mSupervisor.beginDeferResume();
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 c51a46a..e22c419 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -221,7 +221,7 @@
     @Test
     public void testRestartProcessIfVisible() {
         doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.setSavedState(null /* savedState */);
         mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
         prepareFixedAspectRatioUnresizableActivity();
@@ -502,7 +502,7 @@
         mTask.setBounds(100, 100, 400, 600);
         mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
         mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         ensureActivityConfiguration();
 
         final Rect bounds = new Rect(mActivity.getBounds());
@@ -547,7 +547,7 @@
                 .when(mActivity).getRequestedOrientation();
         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         ensureActivityConfiguration();
         // The parent configuration doesn't change since the first resolved configuration, so the
         // activity shouldn't be in the size compatibility mode.
@@ -589,7 +589,7 @@
                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                 .setMaxAspectRatio(1.5f)
                 .build();
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
 
         final Rect originalBounds = new Rect(mActivity.getBounds());
         final int originalDpi = mActivity.getConfiguration().densityDpi;
@@ -614,7 +614,7 @@
         mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
         mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
         mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
 
         ensureActivityConfiguration();
         final Rect originalBounds = new Rect(mActivity.getBounds());
@@ -661,7 +661,7 @@
 
         prepareFixedAspectRatioUnresizableActivity();
         mActivity.setState(STOPPED, "testSizeCompatMode");
-        mActivity.visible = false;
+        mActivity.mVisibleRequested = false;
         mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
         // Make the parent bounds to be different so the activity is in size compatibility mode.
         setupDisplayAndParentSize(600, 1200);
@@ -829,7 +829,7 @@
         // Prepare the activity record to be ready for immediate removal. It should be invisible and
         // have no process. Otherwise, request to finish it will send a message to client first.
         mActivity.setState(STOPPED, "test");
-        mActivity.visible = false;
+        mActivity.mVisibleRequested = false;
         mActivity.nowVisible = false;
         // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
         // this will cause NPE when updating task's process.
@@ -838,7 +838,7 @@
         // Put a visible activity on top, so the finishing activity doesn't have to wait until the
         // next activity reports idle to destroy it.
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = true;
+        topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.setState(RESUMED, "test");
 
@@ -924,7 +924,7 @@
     @Test
     public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
         mActivity.finishing = false;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.setState(RESUMED, "test");
         mActivity.finishIfPossible("test", false /* oomAdj */);
 
@@ -940,7 +940,7 @@
     @Test
     public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
         mActivity.finishing = false;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.setState(PAUSED, "test");
         mActivity.finishIfPossible("test", false /* oomAdj */);
 
@@ -958,7 +958,7 @@
         // Put an activity on top of test activity to make it invisible and prevent us from
         // accidentally resuming the topmost one again.
         new ActivityBuilder(mService).build();
-        mActivity.visible = false;
+        mActivity.mVisibleRequested = false;
         mActivity.setState(STOPPED, "test");
 
         mActivity.finishIfPossible("test", false /* oomAdj */);
@@ -1010,7 +1010,7 @@
     @Test
     public void testCompleteFinishing_keepStateOfNextInvisible() {
         final ActivityRecord currentTop = mActivity;
-        currentTop.visible = currentTop.nowVisible = true;
+        currentTop.mVisibleRequested = currentTop.nowVisible = true;
 
         // Simulates that {@code currentTop} starts an existing activity from background (so its
         // state is stopped) and the starting flow just goes to place it at top.
@@ -1036,13 +1036,13 @@
     @Test
     public void testCompleteFinishing_waitForNextVisible() {
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = true;
+        topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
         topActivity.setState(PAUSED, "true");
         // Mark the bottom activity as not visible, so that we will wait for it before removing
         // the top one.
-        mActivity.visible = false;
+        mActivity.mVisibleRequested = false;
         mActivity.nowVisible = false;
         mActivity.setState(STOPPED, "test");
 
@@ -1061,13 +1061,13 @@
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = false;
+        topActivity.mVisibleRequested = false;
         topActivity.nowVisible = false;
         topActivity.finishing = true;
         topActivity.setState(PAUSED, "true");
         // Mark the bottom activity as not visible, so that we would wait for it before removing
         // the top one.
-        mActivity.visible = false;
+        mActivity.mVisibleRequested = false;
         mActivity.nowVisible = false;
         mActivity.setState(STOPPED, "test");
 
@@ -1083,12 +1083,12 @@
     @Test
     public void testCompleteFinishing_waitForIdle() {
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = true;
+        topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
         topActivity.setState(PAUSED, "true");
         // Mark the bottom activity as already visible, so that there is no need to wait for it.
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.nowVisible = true;
         mActivity.setState(RESUMED, "test");
 
@@ -1104,12 +1104,12 @@
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_stopped() {
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = false;
+        topActivity.mVisibleRequested = false;
         topActivity.nowVisible = false;
         topActivity.finishing = true;
         topActivity.setState(STOPPED, "true");
         // Mark the bottom activity as already visible, so that there is no need to wait for it.
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.nowVisible = true;
         mActivity.setState(RESUMED, "test");
 
@@ -1125,12 +1125,12 @@
     @Test
     public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
-        topActivity.visible = true;
+        topActivity.mVisibleRequested = true;
         topActivity.nowVisible = true;
         topActivity.finishing = true;
         topActivity.setState(PAUSED, "true");
         // Mark the bottom activity as already visible, so that there is no need to wait for it.
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         mActivity.nowVisible = true;
         mActivity.setState(RESUMED, "test");
 
@@ -1139,7 +1139,7 @@
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
         final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
         focusedActivity.nowVisible = true;
-        focusedActivity.visible = true;
+        focusedActivity.mVisibleRequested = true;
         focusedActivity.setState(RESUMED, "test");
         stack.mResumedActivity = focusedActivity;
 
@@ -1346,7 +1346,7 @@
         setupDisplayContentForCompatDisplayInsets();
         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         mActivity.info.maxAspectRatio = 1.5f;
-        mActivity.visible = true;
+        mActivity.mVisibleRequested = true;
         ensureActivityConfiguration();
     }
 
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 d0e07b6..fc44652 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1006,7 +1006,7 @@
 
         // There is still an activity1 in stack1 so the activity2 should be added to finishing list
         // that will be destroyed until idle.
-        stack2.getTopActivity().visible = true;
+        stack2.getTopActivity().mVisibleRequested = true;
         final ActivityRecord activity2 = finishTopActivity(stack2);
         assertEquals(STOPPING, activity2.getState());
         assertThat(mSupervisor.mStoppingActivities).contains(activity2);
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 47b39b0..1632681 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -271,7 +271,7 @@
                 doReturn(true).when(activity).occludesParent();
                 mTask.addChild(activity);
                 // Make visible by default...
-                activity.setHidden(false);
+                activity.setVisible(true);
             }
 
             final WindowProcessController wpc = new WindowProcessController(mService,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 6020453..d415f25 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -62,7 +62,7 @@
         final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         translucentOpening.setOccludesParent(false);
-        translucentOpening.setHidden(true);
+        translucentOpening.setVisible(false);
         mDisplayContent.mOpeningApps.add(behind);
         mDisplayContent.mOpeningApps.add(translucentOpening);
         assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
@@ -90,7 +90,7 @@
         final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         translucentOpening.setOccludesParent(false);
-        translucentOpening.setHidden(true);
+        translucentOpening.setVisible(false);
         mDisplayContent.mOpeningApps.add(behind);
         mDisplayContent.mOpeningApps.add(translucentOpening);
         assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
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 bd336ad..d491569 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -252,7 +252,7 @@
     @Test
     @Presubmit
     public void testGetOrientation() {
-        mActivity.setHidden(false);
+        mActivity.setVisible(true);
 
         mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
@@ -261,7 +261,7 @@
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation());
 
         mActivity.setOccludesParent(true);
-        mActivity.setHidden(true);
+        mActivity.setVisible(false);
         mActivity.sendingToBottom = true;
         // Can not specify orientation if app isn't visible even though it occludes parent.
         assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation());
@@ -314,7 +314,7 @@
 
     @Test
     public void testSetOrientation() {
-        mActivity.setHidden(false);
+        mActivity.setVisible(true);
 
         // Assert orientation is unspecified to start.
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation());
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 ab9a7ca..8db4858 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -26,6 +26,7 @@
 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.Surface.ROTATION_90;
 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_STICKY;
@@ -62,6 +63,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.annotation.SuppressLint;
@@ -70,11 +72,14 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.metrics.LogMaker;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
 import android.view.Gravity;
+import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayWindowRotationController;
 import android.view.ISystemGestureExclusionListener;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -389,7 +394,7 @@
         assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
 
         // Make sure top focused display not changed if there is a focused app.
-        window1.mActivityRecord.hiddenRequested = true;
+        window1.mActivityRecord.mVisibleRequested = false;
         window1.getDisplayContent().setFocusedApp(window1.mActivityRecord);
         updateFocusedWindow();
         assertTrue(!window1.isFocused());
@@ -656,7 +661,7 @@
 
         portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
         assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
-        portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
+        portraitDisplay.getDisplayRotation().setRotation(ROTATION_90);
         assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
 
         final DisplayContent landscapeDisplay = createNewDisplay();
@@ -665,7 +670,7 @@
 
         landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
         assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
-        landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
+        landscapeDisplay.getDisplayRotation().setRotation(ROTATION_90);
         assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
     }
 
@@ -917,6 +922,45 @@
                 is(Configuration.ORIENTATION_PORTRAIT));
     }
 
+    @Test
+    public void testRemoteRotation() {
+        DisplayContent dc = createNewDisplay();
+
+        final DisplayRotation dr = dc.getDisplayRotation();
+        Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+        Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
+        final boolean[] continued = new boolean[1];
+        spyOn(dc.mActivityDisplay);
+        Mockito.doAnswer(
+                invocation -> {
+                    continued[0] = true;
+                    return true;
+                }).when(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked();
+        final boolean[] called = new boolean[1];
+        mWm.mDisplayRotationController =
+                new IDisplayWindowRotationController.Stub() {
+                    @Override
+                    public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+                            IDisplayWindowRotationCallback callback) {
+                        called[0] = true;
+
+                        try {
+                            callback.continueRotateDisplay(toRotation, null);
+                        } catch (RemoteException e) {
+                            assertTrue(false);
+                        }
+                    }
+                };
+
+        // kill any existing rotation animation (vestigial from test setup).
+        dc.setRotationAnimation(null);
+
+        mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
+        assertTrue(called[0]);
+        waitUntilHandlersIdle();
+        assertTrue(continued[0]);
+    }
+
     private boolean isOptionsPanelAtRight(int displayId) {
         return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
     }
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 67b7a66..62ab11c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -515,18 +515,16 @@
         final Rect outFrame = new Rect();
         final Rect outContentInsets = new Rect();
         final Rect outStableInsets = new Rect();
-        final Rect outOutsets = new Rect();
         final DisplayCutout.ParcelableWrapper outDisplayCutout =
                 new DisplayCutout.ParcelableWrapper();
 
         mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
                 false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                outOutsets, outDisplayCutout);
+                outDisplayCutout);
 
         assertThat(outFrame, is(mFrames.mUnrestricted));
         assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
         assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
-        assertThat(outOutsets, is(new Rect()));
         assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
@@ -540,18 +538,16 @@
         final Rect outFrame = new Rect();
         final Rect outContentInsets = new Rect();
         final Rect outStableInsets = new Rect();
-        final Rect outOutsets = new Rect();
         final DisplayCutout.ParcelableWrapper outDisplayCutout =
                 new DisplayCutout.ParcelableWrapper();
 
         mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
                 false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                outOutsets, outDisplayCutout);
+                outDisplayCutout);
 
         assertThat(outFrame, is(taskBounds));
         assertThat(outContentInsets, is(new Rect()));
         assertThat(outStableInsets, is(new Rect()));
-        assertThat(outOutsets, is(new Rect()));
         assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
@@ -568,18 +564,16 @@
         final Rect outFrame = new Rect();
         final Rect outContentInsets = new Rect();
         final Rect outStableInsets = new Rect();
-        final Rect outOutsets = new Rect();
         final DisplayCutout.ParcelableWrapper outDisplayCutout =
                 new DisplayCutout.ParcelableWrapper();
 
         mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
                 true /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                outOutsets, outDisplayCutout);
+                outDisplayCutout);
 
         assertThat(outFrame, is(taskBounds));
         assertThat(outContentInsets, is(new Rect()));
         assertThat(outStableInsets, is(new Rect()));
-        assertThat(outOutsets, is(new Rect()));
         assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 703ebc9..e375f83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -277,47 +277,6 @@
     }
 
     @Test
-    public void testDefaultToZeroOverscan() {
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-
-        assertOverscan(mPrimaryDisplay, 0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
-    }
-
-    @Test
-    public void testPersistOverscanInSameInstance() {
-        final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
-        try {
-            mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */,
-                    4 /* bottom */);
-
-            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-
-            assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */,
-                    4 /* bottom */);
-        } finally {
-            mTarget.setOverscanLocked(info, 0, 0, 0, 0);
-            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-        }
-    }
-
-    @Test
-    public void testPersistOverscanAcrossInstances() {
-        final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
-        try {
-            mTarget.setOverscanLocked(info, 10 /* left */, 20 /* top */, 30 /* right */,
-                    40 /* bottom */);
-
-            applySettingsToDisplayByNewInstance(mPrimaryDisplay);
-
-            assertOverscan(mPrimaryDisplay, 10 /* left */, 20 /* top */, 30 /* right */,
-                    40 /* bottom */);
-        } finally {
-            mTarget.setOverscanLocked(info, 0, 0, 0, 0);
-            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-        }
-    }
-
-    @Test
     public void testDefaultToFreeUserRotation() {
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
@@ -690,16 +649,6 @@
         return null;
     }
 
-    private static void assertOverscan(DisplayContent display, int left, int top, int right,
-            int bottom) {
-        final DisplayInfo info = display.getDisplayInfo();
-
-        assertEquals(left, info.overscanLeft);
-        assertEquals(top, info.overscanTop);
-        assertEquals(right, info.overscanRight);
-        assertEquals(bottom, info.overscanBottom);
-    }
-
     /**
      * This method helps to ensure read and write persistent settings successfully because the
      * constructor of {@link DisplayWindowSettings} should read the persistent file from the given
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 7026004..1abd366 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -149,7 +149,7 @@
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         final ActivityRecord hiddenActivity = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-        hiddenActivity.setHidden(true);
+        hiddenActivity.setVisible(false);
         mDisplayContent.getConfiguration().windowConfiguration.setRotation(
                 mDisplayContent.getRotation());
         mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
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 41cbd81..06d96fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -106,12 +106,12 @@
         RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
                 mRecentsComponent, true /* getRecentsAnimation */);
         // The launch-behind state should make the recents activity visible.
-        assertTrue(recentActivity.visible);
+        assertTrue(recentActivity.mVisibleRequested);
 
         // Simulate the animation is cancelled without changing the stack order.
         recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
         // The non-top recents activity should be invisible by the restored launch-behind state.
-        assertFalse(recentActivity.visible);
+        assertFalse(recentActivity.mVisibleRequested);
     }
 
     @Test
@@ -158,7 +158,7 @@
         // The activity is started in background so it should be invisible and will be stopped.
         assertThat(recentsActivity).isNotNull();
         assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
-        assertFalse(recentsActivity.visible);
+        assertFalse(recentsActivity.mVisibleRequested);
 
         // Assume it is stopped to test next use case.
         recentsActivity.activityStoppedLocked(null /* newIcicle */, null /* newPersistentState */,
@@ -361,7 +361,7 @@
                 true);
 
         // Ensure we find the task for the right user and it is made visible
-        assertTrue(otherUserHomeActivity.visible);
+        assertTrue(otherUserHomeActivity.mVisibleRequested);
     }
 
     private void startRecentsActivity() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 6a94137..e1475a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -37,8 +37,8 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
+    public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+            Rect stableInsets, boolean reportDraw, MergedConfiguration mergedConfig,
             Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
             DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 428d869..0b8b6a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -150,7 +150,7 @@
         // When mFrame extends past cf, the content insets are
         // the difference between mFrame and ContentFrame. Visible
         // and stable frames work the same way.
-        w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
         w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
         assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
@@ -186,7 +186,7 @@
 
         // Here the window has FILL_PARENT, FILL_PARENT
         // so we expect it to fill the entire available frame.
-        w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf);
         w.computeFrameLw();
         assertFrame(w, 0, 0, 1000, 1000);
 
@@ -274,7 +274,7 @@
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
-        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         w.computeFrameLw();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
@@ -287,7 +287,7 @@
         final int cfRight = logicalWidth / 2;
         final int cfBottom = logicalHeight / 2;
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
-        windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+        windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
         w.computeFrameLw();
         assertEquals(resolvedTaskBounds, w.getFrameLw());
         int contentInsetRight = resolvedTaskBounds.right - cfRight;
@@ -306,7 +306,7 @@
         final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
         task.setOverrideDisplayedBounds(resolvedTaskBounds);
         task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
-        windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+        windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
         w.computeFrameLw();
         assertEquals(resolvedTaskBounds, w.getFrameLw());
         contentInsetRight = insetRight - cfRight;
@@ -328,7 +328,6 @@
         final int logicalHeight = displayInfo.logicalHeight;
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final Rect df = pf;
-        final Rect of = df;
         final Rect cf = new Rect(pf);
         // Produce some insets
         cf.top += displayInfo.logicalWidth / 10;
@@ -339,7 +338,7 @@
         Rect dcf = new Rect(cf);
 
         final WindowFrames windowFrames = w.getWindowFrames();
-        windowFrames.setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
         w.computeFrameLw();
         assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
 
@@ -353,7 +352,7 @@
         // we need to account for the fact the windows surface will be made
         // fullscreen and thus also make the crop fullscreen.
 
-        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
         w.mAttrs.width = logicalWidth / 2;
         w.mAttrs.height = logicalHeight / 2;
@@ -395,7 +394,7 @@
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
-        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         w.computeFrameLw();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
@@ -413,7 +412,7 @@
         pf.set(0, 0, logicalWidth, logicalHeight);
         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         task.setBounds(null);
-        windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+        windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
         w.computeFrameLw();
         assertFrame(w, cf);
         assertContentFrame(w, cf);
@@ -434,7 +433,7 @@
                 pf.width(), pf.height());
 
         final WindowFrames windowFrames = w.getWindowFrames();
-        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         windowFrames.setDisplayCutout(cutout);
         w.computeFrameLw();
 
@@ -461,7 +460,7 @@
                 pf.width(), pf.height());
 
         final WindowFrames windowFrames = w.getWindowFrames();
-        windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+        windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
         windowFrames.setDisplayCutout(cutout);
         w.computeFrameLw();
 
@@ -501,7 +500,7 @@
         final Rect winRect = new Rect(200, 200, 300, 500);
 
         task.setBounds(winRect);
-        w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
         w.computeFrameLw();
 
         final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
@@ -514,7 +513,7 @@
         winRect.bottom = 600;
         task.setBounds(winRect);
         w.setBounds(winRect);
-        w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+        w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
         w.computeFrameLw();
 
         assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
@@ -524,7 +523,7 @@
         assertVisibleFrame(w, expected);
 
         // Check that it's moved back without ime insets
-        w.getWindowFrames().setFrames(pf, df, of, pf, pf, dcf, sf, mEmptyRect);
+        w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf);
         w.computeFrameLw();
         assertEquals(winRect, w.getFrameLw());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e1f92dd..0b7cbce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -383,11 +383,11 @@
     @Test
     public void testCanAffectSystemUiFlags() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        app.mToken.setHidden(false);
+        app.mActivityRecord.setVisible(true);
         assertTrue(app.canAffectSystemUiFlags());
-        app.mToken.setHidden(true);
+        app.mActivityRecord.setVisible(false);
         assertFalse(app.canAffectSystemUiFlags());
-        app.mToken.setHidden(false);
+        app.mActivityRecord.setVisible(true);
         app.mAttrs.alpha = 0.0f;
         assertFalse(app.canAffectSystemUiFlags());
     }
@@ -395,7 +395,7 @@
     @Test
     public void testCanAffectSystemUiFlags_disallow() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        app.mToken.setHidden(false);
+        app.mActivityRecord.setVisible(true);
         assertTrue(app.canAffectSystemUiFlags());
         app.getTask().setCanAffectSystemUiFlags(false);
         assertFalse(app.canAffectSystemUiFlags());
@@ -569,7 +569,7 @@
     @Test
     public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
         final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
-        win0.mActivityRecord.hiddenRequested = true;
+        win0.mActivityRecord.mVisibleRequested = false;
         assertTrue(win0.cantReceiveTouchInput());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 797a6bc..26743c8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -74,8 +74,8 @@
     private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
         activity.onDisplayChanged(dc);
         activity.setOccludesParent(true);
-        activity.setHidden(false);
-        activity.hiddenRequested = false;
+        activity.setVisible(true);
+        activity.mVisibleRequested = true;
     }
 
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 24b4046..3ecf8d7 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -25,8 +25,11 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.telecom.IVideoProvider;
+
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
@@ -2132,13 +2135,22 @@
             cannedTextResponsesChanged = true;
         }
 
-        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
-                mTargetSdkVersion);
-        boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
-                !Objects.equals(mVideoCallImpl, newVideoCallImpl);
+        IVideoProvider previousVideoProvider = mVideoCallImpl == null ? null :
+                mVideoCallImpl.getVideoProvider();
+        IVideoProvider newVideoProvider = parcelableCall.getVideoProvider();
+
+        // parcelableCall.isVideoCallProviderChanged is only true when we have a video provider
+        // specified; so we should check if the actual IVideoProvider changes as well.
+        boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged()
+                && !Objects.equals(previousVideoProvider, newVideoProvider);
         if (videoCallChanged) {
-            mVideoCallImpl = newVideoCallImpl;
+            if (mVideoCallImpl != null) {
+                mVideoCallImpl.destroy();
+            }
+            mVideoCallImpl = parcelableCall.isVideoCallProviderChanged() ?
+                    parcelableCall.getVideoCallImpl(mCallingPackage, mTargetSdkVersion) : null;
         }
+
         if (mVideoCallImpl != null) {
             mVideoCallImpl.setVideoState(getDetails().getVideoState());
         }
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index ef1c790..b91787c 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -106,8 +106,14 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
-                        onScreenCall(
-                                Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
+                        Call.Details callDetails = Call.Details
+                                .createFromParcelableCall((ParcelableCall) args.arg2);
+                        onScreenCall(callDetails);
+                        if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) {
+                            mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(this, "Exception when screening call: " + e);
                     } finally {
                         args.recycle();
                     }
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index aa50991..fdc3243 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
@@ -225,6 +226,10 @@
         return mVideoCall;
     }
 
+    public IVideoProvider getVideoProvider() {
+        return mVideoCallProvider;
+    }
+
     public boolean getIsRttCallChanged() {
         return mIsRttCallChanged;
     }
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index cb74012..4a1aa0a 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -32,6 +32,8 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
+import java.util.NoSuchElementException;
+
 /**
  * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
  * {@link Connection.VideoProvider}, and direct callbacks from the
@@ -53,7 +55,11 @@
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
         public void binderDied() {
-            mVideoProvider.asBinder().unlinkToDeath(this, 0);
+            try {
+                mVideoProvider.asBinder().unlinkToDeath(this, 0);
+            } catch (NoSuchElementException nse) {
+                // Already unlinked in destroy below.
+            }
         }
     };
 
@@ -222,6 +228,11 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     public void destroy() {
         unregisterCallback(mCallback);
+        try {
+            mVideoProvider.asBinder().unlinkToDeath(mDeathRecipient, 0);
+        } catch (NoSuchElementException nse) {
+            // Already unlinked in binderDied above.
+        }
     }
 
     /** {@inheritDoc} */
@@ -353,4 +364,12 @@
     public void setVideoState(int videoState) {
         mVideoState = videoState;
     }
+
+    /**
+     * Get the video provider binder.
+     * @return the video provider binder.
+     */
+    public IVideoProvider getVideoProvider() {
+        return mVideoProvider;
+    }
 }
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
index db2f659..883c172 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -27,8 +27,8 @@
 import android.util.EventLog;
 import android.util.EventLog.Event;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import dalvik.system.DexClassLoader;
 
@@ -91,7 +91,7 @@
 
     @BeforeClass
     public static void setUpAll() {
-        sContext = InstrumentationRegistry.getTargetContext();
+        sContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
         sMyUid = android.os.Process.myUid();
     }
 
@@ -331,7 +331,7 @@
 
     // Abstract out the logic for running a native code loading test multiple times if needed and
     // leaving time for audit messages to reach the log.
-    private abstract class TestNativeCodeWithRetries {
+    private abstract static class TestNativeCodeWithRetries {
         String mExpectedContentHash;
         String mExpectedNameHash;
 
diff --git a/tests/WindowManagerStressTest/Android.bp b/tests/WindowManagerStressTest/Android.bp
deleted file mode 100644
index 98749a7..0000000
--- a/tests/WindowManagerStressTest/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-android_test {
-    name: "WindowManagerStressTest",
-    srcs: ["**/*.java"],
-    platform_apis: true,
-}
diff --git a/tests/WindowManagerStressTest/AndroidManifest.xml b/tests/WindowManagerStressTest/AndroidManifest.xml
deleted file mode 100644
index 17e0f15..0000000
--- a/tests/WindowManagerStressTest/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="test.windowmanagerstresstest">
-
-    <application
-        android:allowBackup="false"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"
-        android:supportsRtl="true"
-        android:theme="@style/AppTheme">
-        <activity android:name=".MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/WindowManagerStressTest/res/layout/activity_main.xml b/tests/WindowManagerStressTest/res/layout/activity_main.xml
deleted file mode 100644
index 6cf8269..0000000
--- a/tests/WindowManagerStressTest/res/layout/activity_main.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:paddingBottom="@dimen/activity_vertical_margin"
-    android:paddingLeft="@dimen/activity_horizontal_margin"
-    android:paddingRight="@dimen/activity_horizontal_margin"
-    android:paddingTop="@dimen/activity_vertical_margin"
-    tools:context="test.amslam.MainActivity">
-
-    <Button
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:id="@+id/run"
-        android:text="@string/run" />
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:id="@+id/output" />
-
-</LinearLayout>
diff --git a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bc..0000000
--- a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0c..0000000
--- a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0..0000000
--- a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72c..0000000
--- a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e1..0000000
--- a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/values/colors.xml b/tests/WindowManagerStressTest/res/values/colors.xml
deleted file mode 100644
index 4270ca6..0000000
--- a/tests/WindowManagerStressTest/res/values/colors.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <color name="colorPrimary">#3F51B5</color>
-    <color name="colorPrimaryDark">#303F9F</color>
-    <color name="colorAccent">#FF4081</color>
-</resources>
diff --git a/tests/WindowManagerStressTest/res/values/dimens.xml b/tests/WindowManagerStressTest/res/values/dimens.xml
deleted file mode 100644
index ed4ccbc..0000000
--- a/tests/WindowManagerStressTest/res/values/dimens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <!-- Default screen margins, per the Android Design guidelines. -->
-    <dimen name="activity_horizontal_margin">16dp</dimen>
-    <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
diff --git a/tests/WindowManagerStressTest/res/values/strings.xml b/tests/WindowManagerStressTest/res/values/strings.xml
deleted file mode 100644
index cef05dc..0000000
--- a/tests/WindowManagerStressTest/res/values/strings.xml
+++ /dev/null
@@ -1,19 +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
-  -->
-<resources>
-    <string name="app_name">WmSlam</string>
-    <string name="run">Run</string>
-</resources>
diff --git a/tests/WindowManagerStressTest/res/values/styles.xml b/tests/WindowManagerStressTest/res/values/styles.xml
deleted file mode 100644
index 0983b25..0000000
--- a/tests/WindowManagerStressTest/res/values/styles.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <!-- Base application theme. -->
-    <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
-        <!-- Customize your theme here. -->
-        <item name="android:colorPrimary">@color/colorPrimary</item>
-        <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
-        <item name="android:colorAccent">@color/colorAccent</item>
-    </style>
-</resources>
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
deleted file mode 100644
index 8564698..0000000
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ /dev/null
@@ -1,155 +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 test.windowmanagerstresstest;
-
-import android.app.Activity;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.MergedConfiguration;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.IWindowSession;
-import android.view.InsetsState;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
-import android.widget.TextView;
-
-import com.android.internal.view.BaseIWindow;
-
-import java.util.ArrayList;
-
-public class MainActivity extends Activity {
-
-    private static final String TAG = "WmSlam";
-
-    private TextView mOutput;
-    private volatile boolean finished;
-    private final ArrayList<BaseIWindow> mWindows = new ArrayList<>();
-    private final LayoutParams mLayoutParams = new LayoutParams();
-    private final Rect mTmpRect = new Rect();
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_main);
-        mOutput = (TextView) findViewById(R.id.output);
-
-        findViewById(R.id.run).setOnClickListener(view -> {
-            view.setEnabled(false);
-            mOutput.setText("");
-            startBatch();
-        });
-        mLayoutParams.token = getActivityToken();
-    }
-
-    void startBatch() {
-        new Thread(() -> {
-            finished = false;
-            addWindows();
-            startCpuRunnables();
-            for (int i = 0; i < 5; i++) {
-                final long time = SystemClock.uptimeMillis();
-                slamWm();
-                log("Total: " + (SystemClock.uptimeMillis() - time) + " ms");
-            }
-            removeWindows();
-            finished = true;
-        }).start();
-    }
-
-    void startCpuRunnables() {
-        for (int i = 0; i < 10; i++) {
-            new Thread(mUseCpuRunnable).start();
-        }
-    }
-
-    private final Runnable mUseCpuRunnable = new Runnable() {
-        @Override
-        public void run() {
-            while (!finished) {
-            }
-        }
-    };
-
-    private void log(String text) {
-        mOutput.post(() -> mOutput.append(text + "\n"));
-        Log.d(TAG, text);
-    }
-
-    private void slamWm() {
-        ArrayList<Thread> threads = new ArrayList<>();
-        for (int i = 0; i < 20; i++) {
-            for (BaseIWindow window : mWindows) {
-                Thread t = new Thread(() -> {
-                    try {
-                        WindowManagerGlobal.getWindowSession().relayout(window,
-                                window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect,
-                                mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
-                                new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
-                                new SurfaceControl(), new InsetsState());
-                    } catch (RemoteException e) {
-                        e.printStackTrace();
-                    }
-                });
-                threads.add(t);
-                t.start();
-            }
-        }
-        for (Thread t : threads) {
-            try {
-                t.join();
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    void addWindows() {
-        for (int i = 0; i < 50; i++) {
-            final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
-            layoutParams.token = getActivityToken();
-            final BaseIWindow window = new BaseIWindow();
-            final IWindowSession session = WindowManagerGlobal.getWindowSession();
-            final Rect tmpRect = new Rect();
-            try {
-                final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq,
-                        layoutParams, View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect,
-                        new InsetsState());
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-            mWindows.add(window);
-        }
-    }
-
-    void removeWindows() {
-        for (BaseIWindow window : mWindows) {
-            try {
-                WindowManagerGlobal.getWindowSession().remove(window);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 1f2bb0a..84c5784 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -46,7 +46,6 @@
 import libcore.util.HexEncoding;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -202,14 +201,29 @@
         checkGetConnectionOwnerUid("::1", "::1");
     }
 
-    @Ignore("Times out on Marlin/Sailfish")
     /* Verify fix for b/141603906 */
     @Test
     public void testB141603906() throws Exception {
         final InetSocketAddress src = new InetSocketAddress(0);
         final InetSocketAddress dst = new InetSocketAddress(0);
-        for (int i = 1; i <= 100000; i++) {
-            mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
+        final int numThreads = 8;
+        final int numSockets = 5000;
+        final Thread[] threads = new Thread[numThreads];
+
+        for (int i = 0; i < numThreads; i++) {
+            threads[i] = new Thread(() -> {
+                for (int j = 0; j < numSockets; j++) {
+                    mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
+                }
+            });
+        }
+
+        for (Thread thread : threads) {
+            thread.start();
+        }
+
+        for (Thread thread : threads) {
+            thread.join();
         }
     }
 
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index 05ba8f0..806f4e3 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -404,12 +404,15 @@
 
   for (const auto& entry : keep_set.conditional_class_set_) {
     std::set<UsageLocation> locations;
-    bool can_be_conditional = true;
-    for (const UsageLocation& location : entry.second) {
-      can_be_conditional &= CollectLocations(location, keep_set, &locations);
+    bool can_be_conditional = false;
+    if (keep_set.conditional_keep_rules_) {
+      can_be_conditional = true;
+      for (const UsageLocation& location : entry.second) {
+        can_be_conditional &= CollectLocations(location, keep_set, &locations);
+      }
     }
 
-    if (keep_set.conditional_keep_rules_ && can_be_conditional) {
+    if (can_be_conditional) {
       for (const UsageLocation& location : locations) {
         printer.Print("# Referenced at ").Println(location.source.to_string());
         printer.Print("-if class **.R$layout { int ")